Project
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
imgui.cpp
Go to the documentation of this file.
1 // dear imgui, v1.61
2 // (main code and documentation)
3 
4 // Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp for demo code.
5 // Newcomers, read 'Programmer guide' below for notes on how to setup Dear ImGui in your codebase.
6 // Get latest version at https://github.com/ocornut/imgui
7 // Releases change-log at https://github.com/ocornut/imgui/releases
8 // Gallery (please post your screenshots/video there!): https://github.com/ocornut/imgui/issues/1269
9 // Developed by Omar Cornut and every direct or indirect contributors to the GitHub.
10 // This library is free but I need your support to sustain development and maintenance.
11 // If you work for a company, please consider financial support, see README. For individuals: https://www.patreon.com/imgui
12 
13 // It is recommended that you don't modify imgui.cpp! It will become difficult for you to update the library.
14 // Note that 'ImGui::' being a namespace, you can add functions into the namespace from your own source files, without
15 // modifying imgui.h or imgui.cpp. You may include imgui_internal.h to access internal data structures, but it doesn't
16 // come with any guarantee of forward compatibility. Discussing your changes on the GitHub Issue Tracker may lead you
17 // to a better solution or official support for them.
18 
19 /*
20 
21  Index
22  - MISSION STATEMENT
23  - END-USER GUIDE
24  - PROGRAMMER GUIDE (read me!)
25  - Read first
26  - How to update to a newer version of Dear ImGui
27  - Getting started with integrating Dear ImGui in your code/engine
28  - Using gamepad/keyboard navigation controls [BETA]
29  - API BREAKING CHANGES (read me when you update!)
30  - ISSUES & TODO LIST
31  - FREQUENTLY ASKED QUESTIONS (FAQ), TIPS
32  - How can I tell whether to dispatch mouse/keyboard to imgui or to my application?
33  - How can I display an image? What is ImTextureID, how does it works?
34  - How can I have multiple widgets with the same label or without a label? A primer on labels and the ID Stack.
35  - How can I load a different font than the default?
36  - How can I easily use icons in my application?
37  - How can I load multiple fonts?
38  - How can I display and input non-latin characters such as Chinese, Japanese, Korean, Cyrillic?
39  - How can I use the drawing facilities without an ImGui window? (using ImDrawList API)
40  - I integrated Dear ImGui in my engine and the text or lines are blurry..
41  - I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around..
42  - How can I help?
43  - ISSUES & TODO-LIST
44  - CODE
45 
46 
47  MISSION STATEMENT
48  =================
49 
50  - Easy to use to create code-driven and data-driven tools
51  - Easy to use to create ad hoc short-lived tools and long-lived, more elaborate tools
52  - Easy to hack and improve
53  - Minimize screen real-estate usage
54  - Minimize setup and maintenance
55  - Minimize state storage on user side
56  - Portable, minimize dependencies, run on target (consoles, phones, etc.)
57  - Efficient runtime and memory consumption (NB- we do allocate when "growing" content e.g. creating a window,
58  opening a tree node for the first time, etc. but a typical frame should not allocate anything)
59 
60  Designed for developers and content-creators, not the typical end-user! Some of the weaknesses includes:
61  - Doesn't look fancy, doesn't animate
62  - Limited layout features, intricate layouts are typically crafted in code
63 
64 
65  END-USER GUIDE
66  ==============
67 
68  - Double-click on title bar to collapse window.
69  - Click upper right corner to close a window, available when 'bool* p_open' is passed to ImGui::Begin().
70  - Click and drag on lower right corner to resize window (double-click to auto fit window to its contents).
71  - Click and drag on any empty space to move window.
72  - TAB/SHIFT+TAB to cycle through keyboard editable fields.
73  - CTRL+Click on a slider or drag box to input value as text.
74  - Use mouse wheel to scroll.
75  - Text editor:
76  - Hold SHIFT or use mouse to select text.
77  - CTRL+Left/Right to word jump.
78  - CTRL+Shift+Left/Right to select words.
79  - CTRL+A our Double-Click to select all.
80  - CTRL+X,CTRL+C,CTRL+V to use OS clipboard/
81  - CTRL+Z,CTRL+Y to undo/redo.
82  - ESCAPE to revert text to its original value.
83  - You can apply arithmetic operators +,*,/ on numerical values. Use +- to subtract (because - would set a negative value!)
84  - Controls are automatically adjusted for OSX to match standard OSX text editing operations.
85  - General Keyboard controls: enable with ImGuiConfigFlags_NavEnableKeyboard.
86  - General Gamepad controls: enable with ImGuiConfigFlags_NavEnableGamepad. See suggested mappings in imgui.h ImGuiNavInput_ + download PNG/PSD at http://goo.gl/9LgVZW
87 
88 
89  PROGRAMMER GUIDE
90  ================
91 
92  READ FIRST
93 
94  - Read the FAQ below this section!
95  - Your code creates the UI, if your code doesn't run the UI is gone! The UI can be highly dynamic, there are no construction
96  or destruction steps, less data retention on your side, less state duplication, less state synchronization, less bugs.
97  - Call and read ImGui::ShowDemoWindow() for demo code demonstrating most features.
98  - You can learn about immediate-mode gui principles at http://www.johno.se/book/imgui.html or watch http://mollyrocket.com/861
99 
100  HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI
101 
102  - Overwrite all the sources files except for imconfig.h (if you have made modification to your copy of imconfig.h)
103  - Read the "API BREAKING CHANGES" section (below). This is where we list occasional API breaking changes.
104  If a function/type has been renamed / or marked obsolete, try to fix the name in your code before it is permanently removed
105  from the public API. If you have a problem with a missing function/symbols, search for its name in the code, there will
106  likely be a comment about it. Please report any issue to the GitHub page!
107  - Try to keep your copy of dear imgui reasonably up to date.
108 
109  GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE
110 
111  - Run and study the examples and demo to get acquainted with the library.
112  - Add the Dear ImGui source files to your projects, using your preferred build system.
113  It is recommended you build the .cpp files as part of your project and not as a library.
114  - You can later customize the imconfig.h file to tweak some compilation time behavior, such as integrating imgui types with your own maths types.
115  - You may be able to grab and copy a ready made imgui_impl_*** file from the examples/ folder.
116  - When using Dear ImGui, your programming IDE is your friend: follow the declaration of variables, functions and types to find comments about them.
117 
118  - Init: retrieve the ImGuiIO structure with ImGui::GetIO() and fill the fields marked 'Settings': at minimum you need to set io.DisplaySize
119  (application resolution). Later on you will fill your keyboard mapping, clipboard handlers, and other advanced features but for a basic
120  integration you don't need to worry about it all.
121  - Init: call io.Fonts->GetTexDataAsRGBA32(...), it will build the font atlas texture, then load the texture pixels into graphics memory.
122  - Every frame:
123  - In your main loop as early a possible, fill the IO fields marked 'Input' (e.g. mouse position, buttons, keyboard info, etc.)
124  - Call ImGui::NewFrame() to begin the frame
125  - You can use any ImGui function you want between NewFrame() and Render()
126  - Call ImGui::Render() as late as you can to end the frame and finalize render data. it will call your io.RenderDrawListFn handler.
127  (Even if you don't render, call Render() and ignore the callback, or call EndFrame() instead. Otherwise some features will break)
128  - All rendering information are stored into command-lists until ImGui::Render() is called.
129  - Dear ImGui never touches or knows about your GPU state. the only function that knows about GPU is the RenderDrawListFn handler that you provide.
130  - Effectively it means you can create widgets at any time in your code, regardless of considerations of being in "update" vs "render" phases
131  of your own application.
132  - Refer to the examples applications in the examples/ folder for instruction on how to setup your code.
133  - A minimal application skeleton may be:
134 
135  // Application init
136  ImGui::CreateContext();
137  ImGuiIO& io = ImGui::GetIO();
138  io.DisplaySize.x = 1920.0f;
139  io.DisplaySize.y = 1280.0f;
140  // TODO: Fill others settings of the io structure later.
141 
142  // Load texture atlas (there is a default font so you don't need to care about choosing a font yet)
143  unsigned char* pixels;
144  int width, height;
145  io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
146  // TODO: At this points you've got the texture data and you need to upload that your your graphic system:
147  MyTexture* texture = MyEngine::CreateTextureFromMemoryPixels(pixels, width, height, TEXTURE_TYPE_RGBA)
148  // TODO: Store your texture pointer/identifier (whatever your engine uses) in 'io.Fonts->TexID'. This will be passed back to your via the renderer.
149  io.Fonts->TexID = (void*)texture;
150 
151  // Application main loop
152  while (true)
153  {
154  // Setup low-level inputs (e.g. on Win32, GetKeyboardState(), or write to those fields from your Windows message loop handlers, etc.)
155  ImGuiIO& io = ImGui::GetIO();
156  io.DeltaTime = 1.0f/60.0f;
157  io.MousePos = mouse_pos;
158  io.MouseDown[0] = mouse_button_0;
159  io.MouseDown[1] = mouse_button_1;
160 
161  // Call NewFrame(), after this point you can use ImGui::* functions anytime
162  ImGui::NewFrame();
163 
164  // Most of your application code here
165  MyGameUpdate(); // may use any ImGui functions, e.g. ImGui::Begin("My window"); ImGui::Text("Hello, world!"); ImGui::End();
166  MyGameRender(); // may use any ImGui functions as well!
167 
168  // Render & swap video buffers
169  ImGui::Render();
170  MyImGuiRenderFunction(ImGui::GetDrawData());
171  SwapBuffers();
172  }
173 
174  // Shutdown
175  ImGui::DestroyContext();
176 
177 
178  - A minimal render function skeleton may be:
179 
180  void void MyRenderFunction(ImDrawData* draw_data)
181  {
182  // TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled
183  // TODO: Setup viewport, orthographic projection matrix
184  // TODO: Setup shader: vertex { float2 pos, float2 uv, u32 color }, fragment shader sample color from 1 texture, multiply by vertex color.
185  for (int n = 0; n < draw_data->CmdListsCount; n++)
186  {
187  const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; // vertex buffer generated by ImGui
188  const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; // index buffer generated by ImGui
189  for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
190  {
191  const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
192  if (pcmd->UserCallback)
193  {
194  pcmd->UserCallback(cmd_list, pcmd);
195  }
196  else
197  {
198  // The texture for the draw call is specified by pcmd->TextureId.
199  // The vast majority of draw calls with use the imgui texture atlas, which value you have set yourself during initialization.
200  MyEngineBindTexture(pcmd->TextureId);
201 
202  // We are using scissoring to clip some objects. All low-level graphics API supports it.
203  // If your engine doesn't support scissoring yet, you may ignore this at first. You will get some small glitches
204  // (some elements visible outside their bounds) but you can fix that once everywhere else works!
205  MyEngineScissor((int)pcmd->ClipRect.x, (int)pcmd->ClipRect.y, (int)(pcmd->ClipRect.z - pcmd->ClipRect.x), (int)(pcmd->ClipRect.w - pcmd->ClipRect.y));
206 
207  // Render 'pcmd->ElemCount/3' indexed triangles.
208  // By default the indices ImDrawIdx are 16-bits, you can change them to 32-bits if your engine doesn't support 16-bits indices.
209  MyEngineDrawIndexedTriangles(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer, vtx_buffer);
210  }
211  idx_buffer += pcmd->ElemCount;
212  }
213  }
214  }
215 
216  - The examples/ folders contains many functional implementation of the pseudo-code above.
217  - When calling NewFrame(), the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags are updated.
218  They tell you if ImGui intends to use your inputs. When a flag is set you want to hide the corresponding inputs from the rest of your application.
219  In both cases you need to pass on the inputs to imgui. Read the FAQ below for more information about those flags.
220  - Please read the FAQ above. Amusingly, it is called a FAQ because people frequently have the same issues!
221 
222  USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS [BETA]
223 
224  - The gamepad/keyboard navigation is in Beta. Ask questions and report issues at https://github.com/ocornut/imgui/issues/787
225  - The initial focus was to support game controllers, but keyboard is becoming increasingly and decently usable.
226  - Gamepad:
227  - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad to enable.
228  - Backend: Set io.BackendFlags |= ImGuiBackendFlags_HasGamepad + fill the io.NavInputs[] fields before calling NewFrame().
229  Note that io.NavInputs[] is cleared by EndFrame().
230  - See 'enum ImGuiNavInput_' in imgui.h for a description of inputs. For each entry of io.NavInputs[], set the following values:
231  0.0f= not held. 1.0f= fully held. Pass intermediate 0.0f..1.0f values for analog triggers/sticks.
232  - We uses a simple >0.0f test for activation testing, and won't attempt to test for a dead-zone.
233  Your code will probably need to transform your raw inputs (such as e.g. remapping your 0.2..0.9 raw input range to 0.0..1.0 imgui range, etc.).
234  - You can download PNG/PSD files depicting the gamepad controls for common controllers at: goo.gl/9LgVZW.
235  - If you need to share inputs between your game and the imgui parts, the easiest approach is to go all-or-nothing, with a buttons combo
236  to toggle the target. Please reach out if you think the game vs navigation input sharing could be improved.
237  - Keyboard:
238  - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable.
239  NewFrame() will automatically fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays.
240  - When keyboard navigation is active (io.NavActive + ImGuiConfigFlags_NavEnableKeyboard), the io.WantCaptureKeyboard flag
241  will be set. For more advanced uses, you may want to read from:
242  - io.NavActive: true when a window is focused and it doesn't have the ImGuiWindowFlags_NoNavInputs flag set.
243  - io.NavVisible: true when the navigation cursor is visible (and usually goes false when mouse is used).
244  - or query focus information with e.g. IsWindowFocused(ImGuiFocusedFlags_AnyWindow), IsItemFocused() etc. functions.
245  Please reach out if you think the game vs navigation input sharing could be improved.
246  - Mouse:
247  - PS4 users: Consider emulating a mouse cursor with DualShock4 touch pad or a spare analog stick as a mouse-emulation fallback.
248  - Consoles/Tablet/Phone users: Consider using a Synergy 1.x server (on your PC) + uSynergy.c (on your console/tablet/phone app) to share your PC mouse/keyboard.
249  - On a TV/console system where readability may be lower or mouse inputs may be awkward, you may want to set the ImGuiConfigFlags_NavEnableSetMousePos flag.
250  Enabling ImGuiConfigFlags_NavEnableSetMousePos + ImGuiBackendFlags_HasSetMousePos instructs dear imgui to move your mouse cursor along with navigation movements.
251  When enabled, the NewFrame() function may alter 'io.MousePos' and set 'io.WantSetMousePos' to notify you that it wants the mouse cursor to be moved.
252  When that happens your back-end NEEDS to move the OS or underlying mouse cursor on the next frame. Some of the binding in examples/ do that.
253  (If you set the NavEnableSetMousePos flag but don't honor 'io.WantSetMousePos' properly, imgui will misbehave as it will see your mouse as moving back and forth!)
254  (In a setup when you may not have easy control over the mouse cursor, e.g. uSynergy.c doesn't expose moving remote mouse cursor, you may want
255  to set a boolean to ignore your other external mouse positions until the external source is moved again.)
256 
257 
258  API BREAKING CHANGES
259  ====================
260 
261  Occasionally introducing changes that are breaking the API. We try to make the breakage minor and easy to fix.
262  Below is a change-log of API breaking changes only. If you are using one of the functions listed, expect to have to fix some code.
263  When you are not sure about a old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files.
264  You can read releases logs https://github.com/ocornut/imgui/releases for more details.
265 
266  - 2018/05/03 (1.61) - DragInt(): The default compile-time format string has been changed from "%.0f" to "%d", as we are not using integers internally any more.
267  If you used DragInt() with custom format strings, make sure you change them to use %d or an integer-compatible format.
268  To honor backward-compatibility, the DragInt() code will currently parse and modify format strings to replace %*f with %d, giving time to users to upgrade their code.
269  If you have IMGUI_DISABLE_OBSOLETE_FUNCTIONS enabled, the code will instead assert! You may run a reg-exp search on your codebase for e.g. "DragInt.*%f" to help you find them.
270  - 2018/04/28 (1.61) - obsoleted InputFloat() functions taking an optional "int decimal_precision" in favor of an equivalent and more flexible "const char* format",
271  consistent with other functions. Kept redirection functions (will obsolete).
272  - 2018/04/09 (1.61) - IM_DELETE() helper function added in 1.60 doesn't clear the input _pointer_ reference, more consistent with expectation and allows passing r-value.
273  - 2018/03/20 (1.60) - renamed io.WantMoveMouse to io.WantSetMousePos for consistency and ease of understanding (was added in 1.52, _not_ used by core and only honored by some binding ahead of merging the Nav branch).
274  - 2018/03/12 (1.60) - removed ImGuiCol_CloseButton, ImGuiCol_CloseButtonActive, ImGuiCol_CloseButtonHovered as the closing cross uses regular button colors now.
275  - 2018/03/08 (1.60) - changed ImFont::DisplayOffset.y to default to 0 instead of +1. Fixed rounding of Ascent/Descent to match TrueType renderer. If you were adding or subtracting to ImFont::DisplayOffset check if your fonts are correctly aligned vertically.
276  - 2018/03/03 (1.60) - renamed ImGuiStyleVar_Count_ to ImGuiStyleVar_COUNT and ImGuiMouseCursor_Count_ to ImGuiMouseCursor_COUNT for consistency with other public enums.
277  - 2018/02/18 (1.60) - BeginDragDropSource(): temporarily removed the optional mouse_button=0 parameter because it is not really usable in many situations at the moment.
278  - 2018/02/16 (1.60) - obsoleted the io.RenderDrawListsFn callback, you can call your graphics engine render function after ImGui::Render(). Use ImGui::GetDrawData() to retrieve the ImDrawData* to display.
279  - 2018/02/07 (1.60) - reorganized context handling to be more explicit,
280  - YOU NOW NEED TO CALL ImGui::CreateContext() AT THE BEGINNING OF YOUR APP, AND CALL ImGui::DestroyContext() AT THE END.
281  - removed Shutdown() function, as DestroyContext() serve this purpose.
282  - you may pass a ImFontAtlas* pointer to CreateContext() to share a font atlas between contexts. Otherwise CreateContext() will create its own font atlas instance.
283  - removed allocator parameters from CreateContext(), they are now setup with SetAllocatorFunctions(), and shared by all contexts.
284  - removed the default global context and font atlas instance, which were confusing for users of DLL reloading and users of multiple contexts.
285  - 2018/01/31 (1.60) - moved sample TTF files from extra_fonts/ to misc/fonts/. If you loaded files directly from the imgui repo you may need to update your paths.
286  - 2018/01/11 (1.60) - obsoleted IsAnyWindowHovered() in favor of IsWindowHovered(ImGuiHoveredFlags_AnyWindow). Kept redirection function (will obsolete).
287  - 2018/01/11 (1.60) - obsoleted IsAnyWindowFocused() in favor of IsWindowFocused(ImGuiFocusedFlags_AnyWindow). Kept redirection function (will obsolete).
288  - 2018/01/03 (1.60) - renamed ImGuiSizeConstraintCallback to ImGuiSizeCallback, ImGuiSizeConstraintCallbackData to ImGuiSizeCallbackData.
289  - 2017/12/29 (1.60) - removed CalcItemRectClosestPoint() which was weird and not really used by anyone except demo code. If you need it it's easy to replicate on your side.
290  - 2017/12/24 (1.53) - renamed the emblematic ShowTestWindow() function to ShowDemoWindow(). Kept redirection function (will obsolete).
291  - 2017/12/21 (1.53) - ImDrawList: renamed style.AntiAliasedShapes to style.AntiAliasedFill for consistency and as a way to explicitly break code that manipulate those flag at runtime. You can now manipulate ImDrawList::Flags
292  - 2017/12/21 (1.53) - ImDrawList: removed 'bool anti_aliased = true' final parameter of ImDrawList::AddPolyline() and ImDrawList::AddConvexPolyFilled(). Prefer manipulating ImDrawList::Flags if you need to toggle them during the frame.
293  - 2017/12/14 (1.53) - using the ImGuiWindowFlags_NoScrollWithMouse flag on a child window forwards the mouse wheel event to the parent window, unless either ImGuiWindowFlags_NoInputs or ImGuiWindowFlags_NoScrollbar are also set.
294  - 2017/12/13 (1.53) - renamed GetItemsLineHeightWithSpacing() to GetFrameHeightWithSpacing(). Kept redirection function (will obsolete).
295  - 2017/12/13 (1.53) - obsoleted IsRootWindowFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootWindow). Kept redirection function (will obsolete).
296  - obsoleted IsRootWindowOrAnyChildFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows). Kept redirection function (will obsolete).
297  - 2017/12/12 (1.53) - renamed ImGuiTreeNodeFlags_AllowOverlapMode to ImGuiTreeNodeFlags_AllowItemOverlap. Kept redirection enum (will obsolete).
298  - 2017/12/10 (1.53) - removed SetNextWindowContentWidth(), prefer using SetNextWindowContentSize(). Kept redirection function (will obsolete).
299  - 2017/11/27 (1.53) - renamed ImGuiTextBuffer::append() helper to appendf(), appendv() to appendfv(). If you copied the 'Log' demo in your code, it uses appendv() so that needs to be renamed.
300  - 2017/11/18 (1.53) - Style, Begin: removed ImGuiWindowFlags_ShowBorders window flag. Borders are now fully set up in the ImGuiStyle structure (see e.g. style.FrameBorderSize, style.WindowBorderSize). Use ImGui::ShowStyleEditor() to look them up.
301  Please note that the style system will keep evolving (hopefully stabilizing in Q1 2018), and so custom styles will probably subtly break over time. It is recommended you use the StyleColorsClassic(), StyleColorsDark(), StyleColorsLight() functions.
302  - 2017/11/18 (1.53) - Style: removed ImGuiCol_ComboBg in favor of combo boxes using ImGuiCol_PopupBg for consistency.
303  - 2017/11/18 (1.53) - Style: renamed ImGuiCol_ChildWindowBg to ImGuiCol_ChildBg.
304  - 2017/11/18 (1.53) - Style: renamed style.ChildWindowRounding to style.ChildRounding, ImGuiStyleVar_ChildWindowRounding to ImGuiStyleVar_ChildRounding.
305  - 2017/11/02 (1.53) - obsoleted IsRootWindowOrAnyChildHovered() in favor of using IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows);
306  - 2017/10/24 (1.52) - renamed IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS/IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS to IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS/IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS for consistency.
307  - 2017/10/20 (1.52) - changed IsWindowHovered() default parameters behavior to return false if an item is active in another window (e.g. click-dragging item from another window to this window). You can use the newly introduced IsWindowHovered() flags to requests this specific behavior if you need it.
308  - 2017/10/20 (1.52) - marked IsItemHoveredRect()/IsMouseHoveringWindow() as obsolete, in favor of using the newly introduced flags for IsItemHovered() and IsWindowHovered(). See https://github.com/ocornut/imgui/issues/1382 for details.
309  removed the IsItemRectHovered()/IsWindowRectHovered() names introduced in 1.51 since they were merely more consistent names for the two functions we are now obsoleting.
310  - 2017/10/17 (1.52) - marked the old 5-parameters version of Begin() as obsolete (still available). Use SetNextWindowSize()+Begin() instead!
311  - 2017/10/11 (1.52) - renamed AlignFirstTextHeightToWidgets() to AlignTextToFramePadding(). Kept inline redirection function (will obsolete).
312  - 2017/09/25 (1.52) - removed SetNextWindowPosCenter() because SetNextWindowPos() now has the optional pivot information to do the same and more. Kept redirection function (will obsolete).
313  - 2017/08/25 (1.52) - io.MousePos needs to be set to ImVec2(-FLT_MAX,-FLT_MAX) when mouse is unavailable/missing. Previously ImVec2(-1,-1) was enough but we now accept negative mouse coordinates. In your binding if you need to support unavailable mouse, make sure to replace "io.MousePos = ImVec2(-1,-1)" with "io.MousePos = ImVec2(-FLT_MAX,-FLT_MAX)".
314  - 2017/08/22 (1.51) - renamed IsItemHoveredRect() to IsItemRectHovered(). Kept inline redirection function (will obsolete). -> (1.52) use IsItemHovered(ImGuiHoveredFlags_RectOnly)!
315  - renamed IsMouseHoveringAnyWindow() to IsAnyWindowHovered() for consistency. Kept inline redirection function (will obsolete).
316  - renamed IsMouseHoveringWindow() to IsWindowRectHovered() for consistency. Kept inline redirection function (will obsolete).
317  - 2017/08/20 (1.51) - renamed GetStyleColName() to GetStyleColorName() for consistency.
318  - 2017/08/20 (1.51) - added PushStyleColor(ImGuiCol idx, ImU32 col) overload, which _might_ cause an "ambiguous call" compilation error if you are using ImColor() with implicit cast. Cast to ImU32 or ImVec4 explicily to fix.
319  - 2017/08/15 (1.51) - marked the weird IMGUI_ONCE_UPON_A_FRAME helper macro as obsolete. prefer using the more explicit ImGuiOnceUponAFrame.
320  - 2017/08/15 (1.51) - changed parameter order for BeginPopupContextWindow() from (const char*,int buttons,bool also_over_items) to (const char*,int buttons,bool also_over_items). Note that most calls relied on default parameters completely.
321  - 2017/08/13 (1.51) - renamed ImGuiCol_Columns*** to ImGuiCol_Separator***. Kept redirection enums (will obsolete).
322  - 2017/08/11 (1.51) - renamed ImGuiSetCond_*** types and flags to ImGuiCond_***. Kept redirection enums (will obsolete).
323  - 2017/08/09 (1.51) - removed ValueColor() helpers, they are equivalent to calling Text(label) + SameLine() + ColorButton().
324  - 2017/08/08 (1.51) - removed ColorEditMode() and ImGuiColorEditMode in favor of ImGuiColorEditFlags and parameters to the various Color*() functions. The SetColorEditOptions() allows to initialize default but the user can still change them with right-click context menu.
325  - changed prototype of 'ColorEdit4(const char* label, float col[4], bool show_alpha = true)' to 'ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags = 0)', where passing flags = 0x01 is a safe no-op (hello dodgy backward compatibility!). - check and run the demo window, under "Color/Picker Widgets", to understand the various new options.
326  - changed prototype of rarely used 'ColorButton(ImVec4 col, bool small_height = false, bool outline_border = true)' to 'ColorButton(const char* desc_id, ImVec4 col, ImGuiColorEditFlags flags = 0, ImVec2 size = ImVec2(0,0))'
327  - 2017/07/20 (1.51) - removed IsPosHoveringAnyWindow(ImVec2), which was partly broken and misleading. ASSERT + redirect user to io.WantCaptureMouse
328  - 2017/05/26 (1.50) - removed ImFontConfig::MergeGlyphCenterV in favor of a more multipurpose ImFontConfig::GlyphOffset.
329  - 2017/05/01 (1.50) - renamed ImDrawList::PathFill() (rarely used directly) to ImDrawList::PathFillConvex() for clarity.
330  - 2016/11/06 (1.50) - BeginChild(const char*) now applies the stack id to the provided label, consistently with other functions as it should always have been. It shouldn't affect you unless (extremely unlikely) you were appending multiple times to a same child from different locations of the stack id. If that's the case, generate an id with GetId() and use it instead of passing string to BeginChild().
331  - 2016/10/15 (1.50) - avoid 'void* user_data' parameter to io.SetClipboardTextFn/io.GetClipboardTextFn pointers. We pass io.ClipboardUserData to it.
332  - 2016/09/25 (1.50) - style.WindowTitleAlign is now a ImVec2 (ImGuiAlign enum was removed). set to (0.5f,0.5f) for horizontal+vertical centering, (0.0f,0.0f) for upper-left, etc.
333  - 2016/07/30 (1.50) - SameLine(x) with x>0.0f is now relative to left of column/group if any, and not always to left of window. This was sort of always the intent and hopefully breakage should be minimal.
334  - 2016/05/12 (1.49) - title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore.
335  If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you.
336  If your TitleBg/TitleBgActive alpha was <1.0f you need to tweak your custom theme to readjust for the fact that we don't draw a WindowBg background behind the title bar.
337  This helper function will convert an old TitleBg/TitleBgActive color into a new one with the same visual output, given the OLD color and the OLD WindowBg color.
338  ImVec4 ConvertTitleBgCol(const ImVec4& win_bg_col, const ImVec4& title_bg_col)
339  {
340  float new_a = 1.0f - ((1.0f - win_bg_col.w) * (1.0f - title_bg_col.w)), k = title_bg_col.w / new_a;
341  return ImVec4((win_bg_col.x * win_bg_col.w + title_bg_col.x) * k, (win_bg_col.y * win_bg_col.w + title_bg_col.y) * k, (win_bg_col.z * win_bg_col.w + title_bg_col.z) * k, new_a);
342  }
343  If this is confusing, pick the RGB value from title bar from an old screenshot and apply this as TitleBg/TitleBgActive. Or you may just create TitleBgActive from a tweaked TitleBg color.
344  - 2016/05/07 (1.49) - removed confusing set of GetInternalState(), GetInternalStateSize(), SetInternalState() functions. Now using CreateContext(), DestroyContext(), GetCurrentContext(), SetCurrentContext().
345  - 2016/05/02 (1.49) - renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(), no redirection.
346  - 2016/05/01 (1.49) - obsoleted old signature of CollapsingHeader(const char* label, const char* str_id = NULL, bool display_frame = true, bool default_open = false) as extra parameters were badly designed and rarely used. You can replace the "default_open = true" flag in new API with CollapsingHeader(label, ImGuiTreeNodeFlags_DefaultOpen).
347  - 2016/04/26 (1.49) - changed ImDrawList::PushClipRect(ImVec4 rect) to ImDraw::PushClipRect(Imvec2 min,ImVec2 max,bool intersect_with_current_clip_rect=false). Note that higher-level ImGui::PushClipRect() is preferable because it will clip at logic/widget level, whereas ImDrawList::PushClipRect() only affect your renderer.
348  - 2016/04/03 (1.48) - removed style.WindowFillAlphaDefault setting which was redundant. Bake default BG alpha inside style.Colors[ImGuiCol_WindowBg] and all other Bg color values. (ref github issue #337).
349  - 2016/04/03 (1.48) - renamed ImGuiCol_TooltipBg to ImGuiCol_PopupBg, used by popups/menus and tooltips. popups/menus were previously using ImGuiCol_WindowBg. (ref github issue #337)
350  - 2016/03/21 (1.48) - renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). Kept inline redirection function (will obsolete).
351  - 2016/03/02 (1.48) - InputText() completion/history/always callbacks: if you modify the text buffer manually (without using DeleteChars()/InsertChars() helper) you need to maintain the BufTextLen field. added an assert.
352  - 2016/01/23 (1.48) - fixed not honoring exact width passed to PushItemWidth(), previously it would add extra FramePadding.x*2 over that width. if you had manual pixel-perfect alignment in place it might affect you.
353  - 2015/12/27 (1.48) - fixed ImDrawList::AddRect() which used to render a rectangle 1 px too large on each axis.
354  - 2015/12/04 (1.47) - renamed Color() helpers to ValueColor() - dangerously named, rarely used and probably to be made obsolete.
355  - 2015/08/29 (1.45) - with the addition of horizontal scrollbar we made various fixes to inconsistencies with dealing with cursor position.
356  GetCursorPos()/SetCursorPos() functions now include the scrolled amount. It shouldn't affect the majority of users, but take note that SetCursorPosX(100.0f) puts you at +100 from the starting x position which may include scrolling, not at +100 from the window left side.
357  GetContentRegionMax()/GetWindowContentRegionMin()/GetWindowContentRegionMax() functions allow include the scrolled amount. Typically those were used in cases where no scrolling would happen so it may not be a problem, but watch out!
358  - 2015/08/29 (1.45) - renamed style.ScrollbarWidth to style.ScrollbarSize
359  - 2015/08/05 (1.44) - split imgui.cpp into extra files: imgui_demo.cpp imgui_draw.cpp imgui_internal.h that you need to add to your project.
360  - 2015/07/18 (1.44) - fixed angles in ImDrawList::PathArcTo(), PathArcToFast() (introduced in 1.43) being off by an extra PI for no justifiable reason
361  - 2015/07/14 (1.43) - add new ImFontAtlas::AddFont() API. For the old AddFont***, moved the 'font_no' parameter of ImFontAtlas::AddFont** functions to the ImFontConfig structure.
362  you need to render your textured triangles with bilinear filtering to benefit from sub-pixel positioning of text.
363  - 2015/07/08 (1.43) - switched rendering data to use indexed rendering. this is saving a fair amount of CPU/GPU and enables us to get anti-aliasing for a marginal cost.
364  this necessary change will break your rendering function! the fix should be very easy. sorry for that :(
365  - if you are using a vanilla copy of one of the imgui_impl_XXXX.cpp provided in the example, you just need to update your copy and you can ignore the rest.
366  - the signature of the io.RenderDrawListsFn handler has changed!
367  old: ImGui_XXXX_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
368  new: ImGui_XXXX_RenderDrawLists(ImDrawData* draw_data).
369  argument: 'cmd_lists' becomes 'draw_data->CmdLists', 'cmd_lists_count' becomes 'draw_data->CmdListsCount'
370  ImDrawList: 'commands' becomes 'CmdBuffer', 'vtx_buffer' becomes 'VtxBuffer', 'IdxBuffer' is new.
371  ImDrawCmd: 'vtx_count' becomes 'ElemCount', 'clip_rect' becomes 'ClipRect', 'user_callback' becomes 'UserCallback', 'texture_id' becomes 'TextureId'.
372  - each ImDrawList now contains both a vertex buffer and an index buffer. For each command, render ElemCount/3 triangles using indices from the index buffer.
373  - if you REALLY cannot render indexed primitives, you can call the draw_data->DeIndexAllBuffers() method to de-index the buffers. This is slow and a waste of CPU/GPU. Prefer using indexed rendering!
374  - refer to code in the examples/ folder or ask on the GitHub if you are unsure of how to upgrade. please upgrade!
375  - 2015/07/10 (1.43) - changed SameLine() parameters from int to float.
376  - 2015/07/02 (1.42) - renamed SetScrollPosHere() to SetScrollFromCursorPos(). Kept inline redirection function (will obsolete).
377  - 2015/07/02 (1.42) - renamed GetScrollPosY() to GetScrollY(). Necessary to reduce confusion along with other scrolling functions, because positions (e.g. cursor position) are not equivalent to scrolling amount.
378  - 2015/06/14 (1.41) - changed ImageButton() default bg_col parameter from (0,0,0,1) (black) to (0,0,0,0) (transparent) - makes a difference when texture have transparence
379  - 2015/06/14 (1.41) - changed Selectable() API from (label, selected, size) to (label, selected, flags, size). Size override should have been rarely be used. Sorry!
380  - 2015/05/31 (1.40) - renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline redirection function (will obsolete).
381  - 2015/05/31 (1.40) - renamed IsRectClipped() to IsRectVisible() for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete).
382  - 2015/05/27 (1.40) - removed the third 'repeat_if_held' parameter from Button() - sorry! it was rarely used and inconsistent. Use PushButtonRepeat(true) / PopButtonRepeat() to enable repeat on desired buttons.
383  - 2015/05/11 (1.40) - changed BeginPopup() API, takes a string identifier instead of a bool. ImGui needs to manage the open/closed state of popups. Call OpenPopup() to actually set the "open" state of a popup. BeginPopup() returns true if the popup is opened.
384  - 2015/05/03 (1.40) - removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same).
385  - 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function until 1.50.
386  - 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API
387  - 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive.
388  - 2014/04/03 (1.38) - removed support for passing -FLT_MAX..+FLT_MAX as the range for a SliderFloat(). Use DragFloat() or Inputfloat() instead.
389  - 2015/03/17 (1.36) - renamed GetItemBoxMin()/GetItemBoxMax()/IsMouseHoveringBox() to GetItemRectMin()/GetItemRectMax()/IsMouseHoveringRect(). Kept inline redirection function until 1.50.
390  - 2015/03/15 (1.36) - renamed style.TreeNodeSpacing to style.IndentSpacing, ImGuiStyleVar_TreeNodeSpacing to ImGuiStyleVar_IndentSpacing
391  - 2015/03/13 (1.36) - renamed GetWindowIsFocused() to IsWindowFocused(). Kept inline redirection function until 1.50.
392  - 2015/03/08 (1.35) - renamed style.ScrollBarWidth to style.ScrollbarWidth (casing)
393  - 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond). Kept inline redirection function until 1.50.
394  - 2015/02/27 (1.34) - renamed ImGuiSetCondition_*** to ImGuiSetCond_***, and _FirstUseThisSession becomes _Once.
395  - 2015/02/11 (1.32) - changed text input callback ImGuiTextEditCallback return type from void-->int. reserved for future use, return 0 for now.
396  - 2015/02/10 (1.32) - renamed GetItemWidth() to CalcItemWidth() to clarify its evolving behavior
397  - 2015/02/08 (1.31) - renamed GetTextLineSpacing() to GetTextLineHeightWithSpacing()
398  - 2015/02/01 (1.31) - removed IO.MemReallocFn (unused)
399  - 2015/01/19 (1.30) - renamed ImGuiStorage::GetIntPtr()/GetFloatPtr() to GetIntRef()/GetIntRef() because Ptr was conflicting with actual pointer storage functions.
400  - 2015/01/11 (1.30) - big font/image API change! now loads TTF file. allow for multiple fonts. no need for a PNG loader.
401  (1.30) - removed GetDefaultFontData(). uses io.Fonts->GetTextureData*() API to retrieve uncompressed pixels.
402  font init: const void* png_data; unsigned int png_size; ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size); <..Upload texture to GPU..>
403  became: unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); <..Upload texture to GPU>; io.Fonts->TexId = YourTextureIdentifier;
404  you now more flexibility to load multiple TTF fonts and manage the texture buffer for internal needs.
405  it is now recommended that you sample the font texture with bilinear interpolation.
406  (1.30) - added texture identifier in ImDrawCmd passed to your render function (we can now render images). make sure to set io.Fonts->TexID.
407  (1.30) - removed IO.PixelCenterOffset (unnecessary, can be handled in user projection matrix)
408  (1.30) - removed ImGui::IsItemFocused() in favor of ImGui::IsItemActive() which handles all widgets
409  - 2014/12/10 (1.18) - removed SetNewWindowDefaultPos() in favor of new generic API SetNextWindowPos(pos, ImGuiSetCondition_FirstUseEver)
410  - 2014/11/28 (1.17) - moved IO.Font*** options to inside the IO.Font-> structure (FontYOffset, FontTexUvForWhite, FontBaseScale, FontFallbackGlyph)
411  - 2014/11/26 (1.17) - reworked syntax of IMGUI_ONCE_UPON_A_FRAME helper macro to increase compiler compatibility
412  - 2014/11/07 (1.15) - renamed IsHovered() to IsItemHovered()
413  - 2014/10/02 (1.14) - renamed IMGUI_INCLUDE_IMGUI_USER_CPP to IMGUI_INCLUDE_IMGUI_USER_INL and imgui_user.cpp to imgui_user.inl (more IDE friendly)
414  - 2014/09/25 (1.13) - removed 'text_end' parameter from IO.SetClipboardTextFn (the string is now always zero-terminated for simplicity)
415  - 2014/09/24 (1.12) - renamed SetFontScale() to SetWindowFontScale()
416  - 2014/09/24 (1.12) - moved IM_MALLOC/IM_REALLOC/IM_FREE preprocessor defines to IO.MemAllocFn/IO.MemReallocFn/IO.MemFreeFn
417  - 2014/08/30 (1.09) - removed IO.FontHeight (now computed automatically)
418  - 2014/08/30 (1.09) - moved IMGUI_FONT_TEX_UV_FOR_WHITE preprocessor define to IO.FontTexUvForWhite
419  - 2014/08/28 (1.09) - changed the behavior of IO.PixelCenterOffset following various rendering fixes
420 
421 
422  ISSUES & TODO-LIST
423  ==================
424  See TODO.txt
425 
426 
427  FREQUENTLY ASKED QUESTIONS (FAQ), TIPS
428  ======================================
429 
430  Q: How can I tell whether to dispatch mouse/keyboard to imgui or to my application?
431  A: You can read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags from the ImGuiIO structure.
432  - When 'io.WantCaptureMouse' is set, imgui wants to use your mouse state, and you may want to discard/hide the inputs from the rest of your application.
433  - When 'io.WantCaptureKeyboard' is set, imgui wants to use your keyboard state, and you may want to discard/hide the inputs from the rest of your application.
434  - When 'io.WantTextInput' is set to may want to notify your OS to popup an on-screen keyboard, if available (e.g. on a mobile phone, or console OS).
435  Note: you should always pass your mouse/keyboard inputs to imgui, even when the io.WantCaptureXXX flag are set false.
436  This is because imgui needs to detect that you clicked in the void to unfocus its windows.
437  Note: The 'io.WantCaptureMouse' is more accurate that any attempt to "check if the mouse is hovering a window" (don't do that!).
438  It handle mouse dragging correctly (both dragging that started over your application or over an imgui window) and handle e.g. modal windows blocking inputs.
439  Those flags are updated by ImGui::NewFrame(). Preferably read the flags after calling NewFrame() if you can afford it, but reading them before is also
440  perfectly fine, as the bool toggle fairly rarely. If you have on a touch device, you might find use for an early call to NewFrameUpdateHoveredWindowAndCaptureFlags().
441  Note: Text input widget releases focus on "Return KeyDown", so the subsequent "Return KeyUp" event that your application receive will typically
442  have 'io.WantCaptureKeyboard=false'. Depending on your application logic it may or not be inconvenient. You might want to track which key-downs
443  were targeted for Dear ImGui, e.g. with an array of bool, and filter out the corresponding key-ups.)
444 
445  Q: How can I display an image? What is ImTextureID, how does it works?
446  A: ImTextureID is a void* used to pass renderer-agnostic texture references around until it hits your render function.
447  Dear ImGui knows nothing about what those bits represent, it just passes them around. It is up to you to decide what you want the void* to carry!
448  It could be an identifier to your OpenGL texture (cast GLuint to void*), a pointer to your custom engine material (cast MyMaterial* to void*), etc.
449  At the end of the chain, your renderer takes this void* to cast it back into whatever it needs to select a current texture to render.
450  Refer to examples applications, where each renderer (in a imgui_impl_xxxx.cpp file) is treating ImTextureID as a different thing.
451  (C++ tip: OpenGL uses integers to identify textures. You can safely store an integer into a void*, just cast it to void*, don't take it's address!)
452  To display a custom image/texture within an ImGui window, you may use ImGui::Image(), ImGui::ImageButton(), ImDrawList::AddImage() functions.
453  Dear ImGui will generate the geometry and draw calls using the ImTextureID that you passed and which your renderer can use.
454  You may call ImGui::ShowMetricsWindow() to explore active draw lists and visualize/understand how the draw data is generated.
455  It is your responsibility to get textures uploaded to your GPU.
456 
457  Q: How can I have multiple widgets with the same label or without a label?
458  A: A primer on labels and the ID Stack...
459 
460  - Elements that are typically not clickable, such as Text() items don't need an ID.
461 
462  - Interactive widgets require state to be carried over multiple frames (most typically Dear ImGui
463  often needs to remember what is the "active" widget). To do so they need a unique ID. Unique ID
464  are typically derived from a string label, an integer index or a pointer.
465 
466  Button("OK"); // Label = "OK", ID = top of id stack + hash of "OK"
467  Button("Cancel"); // Label = "Cancel", ID = top of id stack + hash of "Cancel"
468 
469  - ID are uniquely scoped within windows, tree nodes, etc. which all pushes to the ID stack. Having
470  two buttons labeled "OK" in different windows or different tree locations is fine.
471 
472  - If you have a same ID twice in the same location, you'll have a conflict:
473 
474  Button("OK");
475  Button("OK"); // ID collision! Interacting with either button will trigger the first one.
476 
477  Fear not! this is easy to solve and there are many ways to solve it!
478 
479  - Solving ID conflict in a simple/local context:
480  When passing a label you can optionally specify extra ID information within string itself.
481  Use "##" to pass a complement to the ID that won't be visible to the end-user.
482  This helps solving the simple collision cases when you know e.g. at compilation time which items
483  are going to be created:
485  Button("Play"); // Label = "Play", ID = top of id stack + hash of "Play"
486  Button("Play##foo1"); // Label = "Play", ID = top of id stack + hash of "Play##foo1" (different from above)
487  Button("Play##foo2"); // Label = "Play", ID = top of id stack + hash of "Play##foo2" (different from above)
488 
489  - If you want to completely hide the label, but still need an ID:
490 
491  Checkbox("##On", &b); // Label = "", ID = top of id stack + hash of "##On" (no label!)
492 
493  - Occasionally/rarely you might want change a label while preserving a constant ID. This allows
494  you to animate labels. For example you may want to include varying information in a window title bar,
495  but windows are uniquely identified by their ID. Use "###" to pass a label that isn't part of ID:
496 
497  Button("Hello###ID"; // Label = "Hello", ID = top of id stack + hash of "ID"
498  Button("World###ID"; // Label = "World", ID = top of id stack + hash of "ID" (same as above)
499 
500  sprintf(buf, "My game (%f FPS)###MyGame", fps);
501  Begin(buf); // Variable label, ID = hash of "MyGame"
502 
503  - Solving ID conflict in a more general manner:
504  Use PushID() / PopID() to create scopes and manipulate the ID stack, as to avoid ID conflicts
505  within the same window. This is the most convenient way of distinguishing ID when iterating and
506  creating many UI elements programmatically.
507  You can push a pointer, a string or an integer value into the ID stack.
508  Remember that ID are formed from the concatenation of _everything_ in the ID stack!
509 
510  for (int i = 0; i < 100; i++)
511  {
512  PushID(i);
513  Button("Click"); // Label = "Click", ID = top of id stack + hash of integer + hash of "Click"
514  PopID();
515  }
516 
517  for (int i = 0; i < 100; i++)
518  {
519  MyObject* obj = Objects[i];
520  PushID(obj);
521  Button("Click"); // Label = "Click", ID = top of id stack + hash of pointer + hash of "Click"
522  PopID();
523  }
524 
525  for (int i = 0; i < 100; i++)
526  {
527  MyObject* obj = Objects[i];
528  PushID(obj->Name);
529  Button("Click"); // Label = "Click", ID = top of id stack + hash of string + hash of "Click"
530  PopID();
531  }
532 
533  - More example showing that you can stack multiple prefixes into the ID stack:
534 
535  Button("Click"); // Label = "Click", ID = top of id stack + hash of "Click"
536  PushID("node");
537  Button("Click"); // Label = "Click", ID = top of id stack + hash of "node" + hash of "Click"
538  PushID(my_ptr);
539  Button("Click"); // Label = "Click", ID = top of id stack + hash of "node" + hash of ptr + hash of "Click"
540  PopID();
541  PopID();
542 
543  - Tree nodes implicitly creates a scope for you by calling PushID().
544 
545  Button("Click"); // Label = "Click", ID = top of id stack + hash of "Click"
546  if (TreeNode("node"))
547  {
548  Button("Click"); // Label = "Click", ID = top of id stack + hash of "node" + hash of "Click"
549  TreePop();
550  }
551 
552  - When working with trees, ID are used to preserve the open/close state of each tree node.
553  Depending on your use cases you may want to use strings, indices or pointers as ID.
554  e.g. when following a single pointer that may change over time, using a static string as ID
555  will preserve your node open/closed state when the targeted object change.
556  e.g. when displaying a list of objects, using indices or pointers as ID will preserve the
557  node open/closed state differently. See what makes more sense in your situation!
558 
559  Q: How can I load a different font than the default?
560  A: Use the font atlas to load the TTF/OTF file you want:
561  ImGuiIO& io = ImGui::GetIO();
562  io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels);
563  io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8()
564  (default is ProggyClean.ttf, rendered at size 13, embedded in dear imgui's source code)
565 
566  New programmers: remember that in C/C++ and most programming languages if you want to use a
567  backslash \ within a string literal, you need to write it double backslash "\\":
568  io.Fonts->AddFontFromFileTTF("MyDataFolder\MyFontFile.ttf", size_in_pixels); // WRONG (you are escape the M here!)
569  io.Fonts->AddFontFromFileTTF("MyDataFolder\\MyFontFile.ttf", size_in_pixels); // CORRECT
570  io.Fonts->AddFontFromFileTTF("MyDataFolder/MyFontFile.ttf", size_in_pixels); // ALSO CORRECT
571 
572  Q: How can I easily use icons in my application?
573  A: The most convenient and practical way is to merge an icon font such as FontAwesome inside you
574  main font. Then you can refer to icons within your strings. Read 'How can I load multiple fonts?'
575  and the file 'misc/fonts/README.txt' for instructions and useful header files.
576 
577  Q: How can I load multiple fonts?
578  A: Use the font atlas to pack them into a single texture:
579  (Read misc/fonts/README.txt and the code in ImFontAtlas for more details.)
580 
581  ImGuiIO& io = ImGui::GetIO();
582  ImFont* font0 = io.Fonts->AddFontDefault();
583  ImFont* font1 = io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels);
584  ImFont* font2 = io.Fonts->AddFontFromFileTTF("myfontfile2.ttf", size_in_pixels);
585  io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8()
586  // the first loaded font gets used by default
587  // use ImGui::PushFont()/ImGui::PopFont() to change the font at runtime
588 
589  // Options
590  ImFontConfig config;
591  config.OversampleH = 3;
592  config.OversampleV = 1;
593  config.GlyphOffset.y -= 2.0f; // Move everything by 2 pixels up
594  config.GlyphExtraSpacing.x = 1.0f; // Increase spacing between characters
595  io.Fonts->LoadFromFileTTF("myfontfile.ttf", size_pixels, &config);
596 
597  // Combine multiple fonts into one (e.g. for icon fonts)
598  ImWchar ranges[] = { 0xf000, 0xf3ff, 0 };
599  ImFontConfig config;
600  config.MergeMode = true;
601  io.Fonts->AddFontDefault();
602  io.Fonts->LoadFromFileTTF("fontawesome-webfont.ttf", 16.0f, &config, ranges); // Merge icon font
603  io.Fonts->LoadFromFileTTF("myfontfile.ttf", size_pixels, NULL, &config, io.Fonts->GetGlyphRangesJapanese()); // Merge japanese glyphs
604 
605  Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic?
606  A: When loading a font, pass custom Unicode ranges to specify the glyphs to load.
607 
608  // Add default Japanese ranges
609  io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, NULL, io.Fonts->GetGlyphRangesJapanese());
610 
611  // Or create your own custom ranges (e.g. for a game you can feed your entire game script and only build the characters the game need)
612  ImVector<ImWchar> ranges;
613  ImFontAtlas::GlyphRangesBuilder builder;
614  builder.AddText("Hello world"); // Add a string (here "Hello world" contains 7 unique characters)
615  builder.AddChar(0x7262); // Add a specific character
616  builder.AddRanges(io.Fonts->GetGlyphRangesJapanese()); // Add one of the default ranges
617  builder.BuildRanges(&ranges); // Build the final result (ordered ranges with all the unique characters submitted)
618  io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, NULL, ranges.Data);
619 
620  All your strings needs to use UTF-8 encoding. In C++11 you can encode a string literal in UTF-8
621  by using the u8"hello" syntax. Specifying literal in your source code using a local code page
622  (such as CP-923 for Japanese or CP-1251 for Cyrillic) will NOT work!
623  Otherwise you can convert yourself to UTF-8 or load text data from file already saved as UTF-8.
624 
625  Text input: it is up to your application to pass the right character code by calling
626  io.AddInputCharacter(). The applications in examples/ are doing that. For languages relying
627  on an Input Method Editor (IME), on Windows you can copy the Hwnd of your application in the
628  io.ImeWindowHandle field. The default implementation of io.ImeSetInputScreenPosFn() will set
629  your Microsoft IME position correctly.
630 
631  Q: How can I use the drawing facilities without an ImGui window? (using ImDrawList API)
632  A: - You can create a dummy window. Call SetNextWindowBgAlpha(0.0f), call Begin() with NoTitleBar|NoResize|NoMove|NoScrollbar|NoSavedSettings|NoInputs flags.
633  Then you can retrieve the ImDrawList* via GetWindowDrawList() and draw to it in any way you like.
634  - You can call ImGui::GetOverlayDrawList() and use this draw list to display contents over every other imgui windows.
635  - You can create your own ImDrawList instance. You'll need to initialize them ImGui::GetDrawListSharedData(), or create your own ImDrawListSharedData.
636 
637  Q: I integrated Dear ImGui in my engine and the text or lines are blurry..
638  A: In your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f).
639  Also make sure your orthographic projection matrix and io.DisplaySize matches your actual framebuffer dimension.
640 
641  Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around..
642  A: You are probably mishandling the clipping rectangles in your render function.
643  Rectangles provided by ImGui are defined as (x1=left,y1=top,x2=right,y2=bottom) and NOT as (x1,y1,width,height).
644 
645  Q: How can I help?
646  A: - If you are experienced with Dear ImGui and C++, look at the github issues, or TODO.txt and see how you want/can help!
647  - Convince your company to fund development time! Individual users: you can also become a Patron (patreon.com/imgui) or donate on PayPal! See README.
648  - Disclose your usage of dear imgui via a dev blog post, a tweet, a screenshot, a mention somewhere etc.
649  You may post screenshot or links in the gallery threads (github.com/ocornut/imgui/issues/1269). Visuals are ideal as they inspire other programmers.
650  But even without visuals, disclosing your use of dear imgui help the library grow credibility, and help other teams and programmers with taking decisions.
651  - If you have issues or if you need to hack into the library, even if you don't expect any support it is useful that you share your issues (on github or privately).
652 
653  - tip: you can call Begin() multiple times with the same name during the same frame, it will keep appending to the same window.
654  this is also useful to set yourself in the context of another window (to get/set other settings)
655  - tip: you can create widgets without a Begin()/End() block, they will go in an implicit window called "Debug".
656  - tip: the ImGuiOnceUponAFrame helper will allow run the block of code only once a frame. You can use it to quickly add custom UI in the middle
657  of a deep nested inner loop in your code.
658  - tip: you can call Render() multiple times (e.g for VR renders).
659  - tip: call and read the ShowDemoWindow() code in imgui_demo.cpp for more example of how to use ImGui!
660 
661 */
662 
663 #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
664 #define _CRT_SECURE_NO_WARNINGS
665 #endif
666 
667 #include "imgui.h"
668 #define IMGUI_DEFINE_MATH_OPERATORS
669 #include "imgui_internal.h"
670 
671 #include <ctype.h> // toupper, isprint
672 #include <stdio.h> // vsnprintf, sscanf, printf
673 #if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
674 #include <stddef.h> // intptr_t
675 #else
676 #include <stdint.h> // intptr_t
677 #endif
678 
679 #define IMGUI_DEBUG_NAV_SCORING 0
680 #define IMGUI_DEBUG_NAV_RECTS 0
681 
682 // Visual Studio warnings
683 #ifdef _MSC_VER
684 #pragma warning (disable: 4127) // condition expression is constant
685 #pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff)
686 #pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
687 #endif
688 
689 // Clang warnings with -Weverything
690 #ifdef __clang__
691 #pragma clang diagnostic ignored "-Wunknown-pragmas" // warning : unknown warning group '-Wformat-pedantic *' // not all warnings are known by all clang versions.. so ignoring warnings triggers new warnings on some configuration. great!
692 #pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse.
693 #pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok.
694 #pragma clang diagnostic ignored "-Wformat-nonliteral" // warning : format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code.
695 #pragma clang diagnostic ignored "-Wexit-time-destructors" // warning : declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals.
696 #pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference it.
697 #pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness //
698 #pragma clang diagnostic ignored "-Wformat-pedantic" // warning : format specifies type 'void *' but the argument has type 'xxxx *' // unreasonable, would lead to casting every %p arg to void*. probably enabled by -pedantic.
699 #pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int'
700 #elif defined(__GNUC__)
701 #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
702 #pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size
703 #pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'void*', but argument 6 has type 'ImGuiWindow*'
704 #pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function
705 #pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value
706 #pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked
707 #pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when assuming that (X - c) > X is always false
708 #endif
709 
710 // Enforce cdecl calling convention for functions called by the standard library, in case compilation settings changed the default to e.g. __vectorcall
711 #ifdef _MSC_VER
712 #define IMGUI_CDECL __cdecl
713 #else
714 #define IMGUI_CDECL
715 #endif
716 
717 static const ImS32 IM_S32_MIN = 0x80000000; // INT_MIN;
718 static const ImS32 IM_S32_MAX = 0x7FFFFFFF; // INT_MAX;
719 static const ImU32 IM_U32_MIN = 0;
720 static const ImU32 IM_U32_MAX = 0xFFFFFFFF;
721 static const ImS64 IM_S64_MIN = -9223372036854775807ll - 1ll;
722 static const ImS64 IM_S64_MAX = 9223372036854775807ll;
723 static const ImU64 IM_U64_MIN = 0;
724 static const ImU64 IM_U64_MAX = 0xFFFFFFFFFFFFFFFFull;
725 
726 //-------------------------------------------------------------------------
727 // Forward Declarations
728 //-------------------------------------------------------------------------
729 
730 static bool IsKeyPressedMap(ImGuiKey key, bool repeat = true);
731 
732 static ImFont* GetDefaultFont();
733 static void SetCurrentWindow(ImGuiWindow* window);
734 static void SetWindowScrollX(ImGuiWindow* window, float new_scroll_x);
735 static void SetWindowScrollY(ImGuiWindow* window, float new_scroll_y);
736 static void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond);
737 static void SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond);
738 static void SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond);
739 static ImGuiWindow* FindHoveredWindow();
740 static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFlags flags);
741 static void CheckStacksSize(ImGuiWindow* window, bool write);
742 static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool snap_on_edges);
743 
744 static void AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* draw_list);
745 static void AddWindowToDrawData(ImVector<ImDrawList*>* out_list, ImGuiWindow* window);
746 static void AddWindowToSortedBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window);
747 
748 static ImGuiWindowSettings* AddWindowSettings(const char* name);
749 
750 static ImRect GetViewportRect();
751 
752 static void ClosePopupToLevel(int remaining);
753 
754 static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data);
755 static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end);
756 static ImVec2 InputTextCalcTextSizeW(const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL, ImVec2* out_offset = NULL, bool stop_on_new_line = false);
757 
758 static inline int DataTypeFormatString(char* buf, int buf_size, ImGuiDataType data_type, const void* data_ptr, const char* format);
759 static void DataTypeApplyOp(ImGuiDataType data_type, int op, void* output, void* arg_1, const void* arg_2);
760 static bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* data_ptr, const char* format);
761 
762 namespace ImGui
763 {
764 static void NavUpdate();
765 static void NavUpdateWindowing();
766 static void NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, const ImGuiID id);
767 
768 static void UpdateMovingWindow();
769 static void UpdateMouseInputs();
770 static void UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4]);
771 static void FocusFrontMostActiveWindow(ImGuiWindow* ignore_window);
772 
773 // Template widget behaviors
774 template<typename TYPE, typename SIGNEDTYPE, typename FLOATTYPE>
775 static bool DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const TYPE v_min, const TYPE v_max, const char* format, float power);
776 
777 template<typename TYPE, typename SIGNEDTYPE, typename FLOATTYPE>
778 static bool SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, TYPE* v, const TYPE v_min, const TYPE v_max, const char* format, float power, ImGuiSliderFlags flags);
779 }
780 
781 //-----------------------------------------------------------------------------
782 // Platform dependent default implementations
783 //-----------------------------------------------------------------------------
784 
785 static const char* GetClipboardTextFn_DefaultImpl(void* user_data);
786 static void SetClipboardTextFn_DefaultImpl(void* user_data, const char* text);
787 static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y);
788 
789 //-----------------------------------------------------------------------------
790 // Context
791 //-----------------------------------------------------------------------------
792 
793 // Current context pointer. Implicitly used by all ImGui functions. Always assumed to be != NULL.
794 // CreateContext() will automatically set this pointer if it is NULL. Change to a different context by calling ImGui::SetCurrentContext().
795 // If you use DLL hotreloading you might need to call SetCurrentContext() after reloading code from this file.
796 // ImGui functions are not thread-safe because of this pointer. If you want thread-safety to allow N threads to access N different contexts, you can:
797 // - Change this variable to use thread local storage. You may #define GImGui in imconfig.h for that purpose. Future development aim to make this context pointer explicit to all calls. Also read https://github.com/ocornut/imgui/issues/586
798 // - Having multiple instances of the ImGui code compiled inside different namespace (easiest/safest, if you have a finite number of contexts)
799 #ifndef GImGui
801 #endif
802 
803 // Memory Allocator functions. Use SetAllocatorFunctions() to change them.
804 // If you use DLL hotreloading you might need to call SetAllocatorFunctions() after reloading code from this file.
805 // Otherwise, you probably don't want to modify them mid-program, and if you use global/static e.g. ImVector<> instances you may need to keep them accessible during program destruction.
806 #ifndef IMGUI_DISABLE_DEFAULT_ALLOCATORS
807 static void* MallocWrapper(size_t size, void* user_data) { (void)user_data; return malloc(size); }
808 static void FreeWrapper(void* ptr, void* user_data) { (void)user_data; free(ptr); }
809 #else
810 static void* MallocWrapper(size_t size, void* user_data) { (void)user_data; (void)size; IM_ASSERT(0); return NULL; }
811 static void FreeWrapper(void* ptr, void* user_data) { (void)user_data; (void)ptr; IM_ASSERT(0); }
812 #endif
813 
814 static void* (*GImAllocatorAllocFunc)(size_t size, void* user_data) = MallocWrapper;
815 static void (*GImAllocatorFreeFunc)(void* ptr, void* user_data) = FreeWrapper;
816 static void* GImAllocatorUserData = NULL;
817 static size_t GImAllocatorActiveAllocationsCount = 0;
818 
819 //-----------------------------------------------------------------------------
820 // User facing structures
821 //-----------------------------------------------------------------------------
822 
824 {
825  Alpha = 1.0f; // Global alpha applies to everything in ImGui
826  WindowPadding = ImVec2(8,8); // Padding within a window
827  WindowRounding = 7.0f; // Radius of window corners rounding. Set to 0.0f to have rectangular windows
828  WindowBorderSize = 1.0f; // Thickness of border around windows. Generally set to 0.0f or 1.0f. Other values not well tested.
829  WindowMinSize = ImVec2(32,32); // Minimum window size
830  WindowTitleAlign = ImVec2(0.0f,0.5f);// Alignment for title bar text
831  ChildRounding = 0.0f; // Radius of child window corners rounding. Set to 0.0f to have rectangular child windows
832  ChildBorderSize = 1.0f; // Thickness of border around child windows. Generally set to 0.0f or 1.0f. Other values not well tested.
833  PopupRounding = 0.0f; // Radius of popup window corners rounding. Set to 0.0f to have rectangular child windows
834  PopupBorderSize = 1.0f; // Thickness of border around popup or tooltip windows. Generally set to 0.0f or 1.0f. Other values not well tested.
835  FramePadding = ImVec2(4,3); // Padding within a framed rectangle (used by most widgets)
836  FrameRounding = 0.0f; // Radius of frame corners rounding. Set to 0.0f to have rectangular frames (used by most widgets).
837  FrameBorderSize = 0.0f; // Thickness of border around frames. Generally set to 0.0f or 1.0f. Other values not well tested.
838  ItemSpacing = ImVec2(8,4); // Horizontal and vertical spacing between widgets/lines
839  ItemInnerSpacing = ImVec2(4,4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label)
840  TouchExtraPadding = ImVec2(0,0); // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much!
841  IndentSpacing = 21.0f; // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2).
842  ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns
843  ScrollbarSize = 16.0f; // Width of the vertical scrollbar, Height of the horizontal scrollbar
844  ScrollbarRounding = 9.0f; // Radius of grab corners rounding for scrollbar
845  GrabMinSize = 10.0f; // Minimum width/height of a grab box for slider/scrollbar
846  GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
847  ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text.
848  DisplayWindowPadding = ImVec2(20,20); // Window positions are clamped to be visible within the display area by at least this amount. Only covers regular windows.
849  DisplaySafeAreaPadding = ImVec2(3,3); // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows.
850  MouseCursorScale = 1.0f; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later.
851  AntiAliasedLines = true; // Enable anti-aliasing on lines/borders. Disable if you are really short on CPU/GPU.
852  AntiAliasedFill = true; // Enable anti-aliasing on filled shapes (rounded rectangles, circles, etc.)
853  CurveTessellationTol = 1.25f; // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality.
854 
855  // Default theme
857 }
858 
859 // To scale your entire UI (e.g. if you want your app to use High DPI or generally be DPI aware) you may use this helper function. Scaling the fonts is done separately and is up to you.
860 // Important: This operation is lossy because we round all sizes to integer. If you need to change your scale multiples, call this over a freshly initialized ImGuiStyle structure rather than scaling multiple times.
861 void ImGuiStyle::ScaleAllSizes(float scale_factor)
862 {
863  WindowPadding = ImFloor(WindowPadding * scale_factor);
864  WindowRounding = ImFloor(WindowRounding * scale_factor);
865  WindowMinSize = ImFloor(WindowMinSize * scale_factor);
866  ChildRounding = ImFloor(ChildRounding * scale_factor);
867  PopupRounding = ImFloor(PopupRounding * scale_factor);
868  FramePadding = ImFloor(FramePadding * scale_factor);
869  FrameRounding = ImFloor(FrameRounding * scale_factor);
870  ItemSpacing = ImFloor(ItemSpacing * scale_factor);
871  ItemInnerSpacing = ImFloor(ItemInnerSpacing * scale_factor);
872  TouchExtraPadding = ImFloor(TouchExtraPadding * scale_factor);
873  IndentSpacing = ImFloor(IndentSpacing * scale_factor);
874  ColumnsMinSpacing = ImFloor(ColumnsMinSpacing * scale_factor);
875  ScrollbarSize = ImFloor(ScrollbarSize * scale_factor);
876  ScrollbarRounding = ImFloor(ScrollbarRounding * scale_factor);
877  GrabMinSize = ImFloor(GrabMinSize * scale_factor);
878  GrabRounding = ImFloor(GrabRounding * scale_factor);
879  DisplayWindowPadding = ImFloor(DisplayWindowPadding * scale_factor);
880  DisplaySafeAreaPadding = ImFloor(DisplaySafeAreaPadding * scale_factor);
881  MouseCursorScale = ImFloor(MouseCursorScale * scale_factor);
882 }
883 
885 {
886  // Most fields are initialized with zero
887  memset(this, 0, sizeof(*this));
888 
889  // Settings
890  ConfigFlags = 0x00;
891  BackendFlags = 0x00;
892  DisplaySize = ImVec2(-1.0f, -1.0f);
893  DeltaTime = 1.0f/60.0f;
894  IniSavingRate = 5.0f;
895  IniFilename = "imgui.ini";
896  LogFilename = "imgui_log.txt";
897  MouseDoubleClickTime = 0.30f;
899  for (int i = 0; i < ImGuiKey_COUNT; i++)
900  KeyMap[i] = -1;
901  KeyRepeatDelay = 0.250f;
902  KeyRepeatRate = 0.050f;
903  UserData = NULL;
904 
905  Fonts = NULL;
906  FontGlobalScale = 1.0f;
907  FontDefault = NULL;
908  FontAllowUserScaling = false;
909  DisplayFramebufferScale = ImVec2(1.0f, 1.0f);
911 
912  // Advanced/subtle behaviors
913 #ifdef __APPLE__
914  OptMacOSXBehaviors = true; // Set Mac OS X style defaults based on __APPLE__ compile time flag
915 #else
916  OptMacOSXBehaviors = false;
917 #endif
918  OptCursorBlink = true;
919 
920  // Settings (User Functions)
921  GetClipboardTextFn = GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations
922  SetClipboardTextFn = SetClipboardTextFn_DefaultImpl;
923  ClipboardUserData = NULL;
924  ImeSetInputScreenPosFn = ImeSetInputScreenPosFn_DefaultImpl;
925  ImeWindowHandle = NULL;
926 
927 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
928  RenderDrawListsFn = NULL;
929 #endif
930 
931  // Input (NB: we already have memset zero the entire structure)
932  MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
933  MousePosPrev = ImVec2(-FLT_MAX, -FLT_MAX);
934  MouseDragThreshold = 6.0f;
935  for (int i = 0; i < IM_ARRAYSIZE(MouseDownDuration); i++) MouseDownDuration[i] = MouseDownDurationPrev[i] = -1.0f;
936  for (int i = 0; i < IM_ARRAYSIZE(KeysDownDuration); i++) KeysDownDuration[i] = KeysDownDurationPrev[i] = -1.0f;
937  for (int i = 0; i < IM_ARRAYSIZE(NavInputsDownDuration); i++) NavInputsDownDuration[i] = -1.0f;
938 }
939 
940 // Pass in translated ASCII characters for text input.
941 // - with glfw you can get those from the callback set in glfwSetCharCallback()
942 // - on Windows you can get those using ToAscii+keyboard state, or via the WM_CHAR message
944 {
945  const int n = ImStrlenW(InputCharacters);
946  if (n + 1 < IM_ARRAYSIZE(InputCharacters))
947  {
948  InputCharacters[n] = c;
949  InputCharacters[n+1] = '\0';
950  }
951 }
952 
953 void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
954 {
955  // We can't pass more wchars than ImGuiIO::InputCharacters[] can hold so don't convert more
956  const int wchars_buf_len = sizeof(ImGuiIO::InputCharacters) / sizeof(ImWchar);
957  ImWchar wchars[wchars_buf_len];
958  ImTextStrFromUtf8(wchars, wchars_buf_len, utf8_chars, NULL);
959  for (int i = 0; i < wchars_buf_len && wchars[i] != 0; i++)
960  AddInputCharacter(wchars[i]);
961 }
962 
963 //-----------------------------------------------------------------------------
964 // HELPERS
965 //-----------------------------------------------------------------------------
966 
967 #define IM_STATIC_ASSERT(_COND) typedef char static_assertion_##__line__[(_COND)?1:-1]
968 #define IM_F32_TO_INT8_UNBOUND(_VAL) ((int)((_VAL) * 255.0f + ((_VAL)>=0 ? 0.5f : -0.5f))) // Unsaturated, for display purpose
969 #define IM_F32_TO_INT8_SAT(_VAL) ((int)(ImSaturate(_VAL) * 255.0f + 0.5f)) // Saturated, always output 0..255
970 
971 ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p)
972 {
973  ImVec2 ap = p - a;
974  ImVec2 ab_dir = b - a;
975  float dot = ap.x * ab_dir.x + ap.y * ab_dir.y;
976  if (dot < 0.0f)
977  return a;
978  float ab_len_sqr = ab_dir.x * ab_dir.x + ab_dir.y * ab_dir.y;
979  if (dot > ab_len_sqr)
980  return b;
981  return a + ab_dir * dot / ab_len_sqr;
982 }
983 
984 bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p)
985 {
986  bool b1 = ((p.x - b.x) * (a.y - b.y) - (p.y - b.y) * (a.x - b.x)) < 0.0f;
987  bool b2 = ((p.x - c.x) * (b.y - c.y) - (p.y - c.y) * (b.x - c.x)) < 0.0f;
988  bool b3 = ((p.x - a.x) * (c.y - a.y) - (p.y - a.y) * (c.x - a.x)) < 0.0f;
989  return ((b1 == b2) && (b2 == b3));
990 }
991 
992 void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w)
993 {
994  ImVec2 v0 = b - a;
995  ImVec2 v1 = c - a;
996  ImVec2 v2 = p - a;
997  const float denom = v0.x * v1.y - v1.x * v0.y;
998  out_v = (v2.x * v1.y - v1.x * v2.y) / denom;
999  out_w = (v0.x * v2.y - v2.x * v0.y) / denom;
1000  out_u = 1.0f - out_v - out_w;
1001 }
1002 
1003 ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p)
1004 {
1005  ImVec2 proj_ab = ImLineClosestPoint(a, b, p);
1006  ImVec2 proj_bc = ImLineClosestPoint(b, c, p);
1007  ImVec2 proj_ca = ImLineClosestPoint(c, a, p);
1008  float dist2_ab = ImLengthSqr(p - proj_ab);
1009  float dist2_bc = ImLengthSqr(p - proj_bc);
1010  float dist2_ca = ImLengthSqr(p - proj_ca);
1011  float m = ImMin(dist2_ab, ImMin(dist2_bc, dist2_ca));
1012  if (m == dist2_ab)
1013  return proj_ab;
1014  if (m == dist2_bc)
1015  return proj_bc;
1016  return proj_ca;
1017 }
1018 
1019 int ImStricmp(const char* str1, const char* str2)
1020 {
1021  int d;
1022  while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; }
1023  return d;
1024 }
1025 
1026 int ImStrnicmp(const char* str1, const char* str2, size_t count)
1027 {
1028  int d = 0;
1029  while (count > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; count--; }
1030  return d;
1031 }
1032 
1033 void ImStrncpy(char* dst, const char* src, size_t count)
1034 {
1035  if (count < 1) return;
1036  strncpy(dst, src, count);
1037  dst[count-1] = 0;
1038 }
1039 
1040 char* ImStrdup(const char *str)
1041 {
1042  size_t len = strlen(str) + 1;
1043  void* buf = ImGui::MemAlloc(len);
1044  return (char*)memcpy(buf, (const void*)str, len);
1045 }
1046 
1047 const char* ImStrchrRange(const char* str, const char* str_end, char c)
1048 {
1049  for ( ; str < str_end; str++)
1050  if (*str == c)
1051  return str;
1052  return NULL;
1053 }
1054 
1055 int ImStrlenW(const ImWchar* str)
1056 {
1057  int n = 0;
1058  while (*str++) n++;
1059  return n;
1060 }
1061 
1062 const ImWchar* ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin) // find beginning-of-line
1063 {
1064  while (buf_mid_line > buf_begin && buf_mid_line[-1] != '\n')
1065  buf_mid_line--;
1066  return buf_mid_line;
1067 }
1068 
1069 const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end)
1070 {
1071  if (!needle_end)
1072  needle_end = needle + strlen(needle);
1073 
1074  const char un0 = (char)toupper(*needle);
1075  while ((!haystack_end && *haystack) || (haystack_end && haystack < haystack_end))
1076  {
1077  if (toupper(*haystack) == un0)
1078  {
1079  const char* b = needle + 1;
1080  for (const char* a = haystack + 1; b < needle_end; a++, b++)
1081  if (toupper(*a) != toupper(*b))
1082  break;
1083  if (b == needle_end)
1084  return haystack;
1085  }
1086  haystack++;
1087  }
1088  return NULL;
1089 }
1090 
1091 // Trim str by offsetting contents when there's leading data + writing a \0 at the trailing position. We use this in situation where the cost is negligible.
1093 {
1094  char* p = buf;
1095  while (p[0] == ' ' || p[0] == '\t') // Leading blanks
1096  p++;
1097  char* p_start = p;
1098  while (*p != 0) // Find end of string
1099  p++;
1100  while (p > p_start && (p[-1] == ' ' || p[-1] == '\t')) // Trailing blanks
1101  p--;
1102  if (p_start != buf) // Copy memory if we had leading blanks
1103  memmove(buf, p_start, p - p_start);
1104  buf[p - p_start] = 0; // Zero terminate
1105 }
1106 
1107 template<typename TYPE>
1108 static const char* ImAtoi(const char* src, TYPE* output)
1109 {
1110  int negative = 0;
1111  if (*src == '-') { negative = 1; src++; }
1112  if (*src == '+') { src++; }
1113  TYPE v = 0;
1114  while (*src >= '0' && *src <= '9')
1115  v = (v * 10) + (*src++ - '0');
1116  *output = negative ? -v : v;
1117  return src;
1118 }
1119 
1120 // A) MSVC version appears to return -1 on overflow, whereas glibc appears to return total count (which may be >= buf_size).
1121 // Ideally we would test for only one of those limits at runtime depending on the behavior the vsnprintf(), but trying to deduct it at compile time sounds like a pandora can of worm.
1122 // B) When buf==NULL vsnprintf() will return the output size.
1123 #ifndef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS
1124 int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...)
1125 {
1126  va_list args;
1127  va_start(args, fmt);
1128  int w = vsnprintf(buf, buf_size, fmt, args);
1129  va_end(args);
1130  if (buf == NULL)
1131  return w;
1132  if (w == -1 || w >= (int)buf_size)
1133  w = (int)buf_size - 1;
1134  buf[w] = 0;
1135  return w;
1136 }
1137 
1138 int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args)
1139 {
1140  int w = vsnprintf(buf, buf_size, fmt, args);
1141  if (buf == NULL)
1142  return w;
1143  if (w == -1 || w >= (int)buf_size)
1144  w = (int)buf_size - 1;
1145  buf[w] = 0;
1146  return w;
1147 }
1148 #endif // #ifdef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS
1149 
1150 // Pass data_size==0 for zero-terminated strings
1151 // FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements.
1152 ImU32 ImHash(const void* data, int data_size, ImU32 seed)
1153 {
1154  static ImU32 crc32_lut[256] = { 0 };
1155  if (!crc32_lut[1])
1156  {
1157  const ImU32 polynomial = 0xEDB88320;
1158  for (ImU32 i = 0; i < 256; i++)
1159  {
1160  ImU32 crc = i;
1161  for (ImU32 j = 0; j < 8; j++)
1162  crc = (crc >> 1) ^ (ImU32(-int(crc & 1)) & polynomial);
1163  crc32_lut[i] = crc;
1164  }
1165  }
1166 
1167  seed = ~seed;
1168  ImU32 crc = seed;
1169  const unsigned char* current = (const unsigned char*)data;
1170 
1171  if (data_size > 0)
1172  {
1173  // Known size
1174  while (data_size--)
1175  crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *current++];
1176  }
1177  else
1178  {
1179  // Zero-terminated string
1180  while (unsigned char c = *current++)
1181  {
1182  // We support a syntax of "label###id" where only "###id" is included in the hash, and only "label" gets displayed.
1183  // Because this syntax is rarely used we are optimizing for the common case.
1184  // - If we reach ### in the string we discard the hash so far and reset to the seed.
1185  // - We don't do 'current += 2; continue;' after handling ### to keep the code smaller.
1186  if (c == '#' && current[0] == '#' && current[1] == '#')
1187  crc = seed;
1188  crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c];
1189  }
1190  }
1191  return ~crc;
1192 }
1193 
1194 //-----------------------------------------------------------------------------
1195 // ImText* helpers
1196 //-----------------------------------------------------------------------------
1197 
1198 // Convert UTF-8 to 32-bits character, process single character input.
1199 // Based on stb_from_utf8() from github.com/nothings/stb/
1200 // We handle UTF-8 decoding error by skipping forward.
1201 int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end)
1202 {
1203  unsigned int c = (unsigned int)-1;
1204  const unsigned char* str = (const unsigned char*)in_text;
1205  if (!(*str & 0x80))
1206  {
1207  c = (unsigned int)(*str++);
1208  *out_char = c;
1209  return 1;
1210  }
1211  if ((*str & 0xe0) == 0xc0)
1212  {
1213  *out_char = 0xFFFD; // will be invalid but not end of string
1214  if (in_text_end && in_text_end - (const char*)str < 2) return 1;
1215  if (*str < 0xc2) return 2;
1216  c = (unsigned int)((*str++ & 0x1f) << 6);
1217  if ((*str & 0xc0) != 0x80) return 2;
1218  c += (*str++ & 0x3f);
1219  *out_char = c;
1220  return 2;
1221  }
1222  if ((*str & 0xf0) == 0xe0)
1223  {
1224  *out_char = 0xFFFD; // will be invalid but not end of string
1225  if (in_text_end && in_text_end - (const char*)str < 3) return 1;
1226  if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return 3;
1227  if (*str == 0xed && str[1] > 0x9f) return 3; // str[1] < 0x80 is checked below
1228  c = (unsigned int)((*str++ & 0x0f) << 12);
1229  if ((*str & 0xc0) != 0x80) return 3;
1230  c += (unsigned int)((*str++ & 0x3f) << 6);
1231  if ((*str & 0xc0) != 0x80) return 3;
1232  c += (*str++ & 0x3f);
1233  *out_char = c;
1234  return 3;
1235  }
1236  if ((*str & 0xf8) == 0xf0)
1237  {
1238  *out_char = 0xFFFD; // will be invalid but not end of string
1239  if (in_text_end && in_text_end - (const char*)str < 4) return 1;
1240  if (*str > 0xf4) return 4;
1241  if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf)) return 4;
1242  if (*str == 0xf4 && str[1] > 0x8f) return 4; // str[1] < 0x80 is checked below
1243  c = (unsigned int)((*str++ & 0x07) << 18);
1244  if ((*str & 0xc0) != 0x80) return 4;
1245  c += (unsigned int)((*str++ & 0x3f) << 12);
1246  if ((*str & 0xc0) != 0x80) return 4;
1247  c += (unsigned int)((*str++ & 0x3f) << 6);
1248  if ((*str & 0xc0) != 0x80) return 4;
1249  c += (*str++ & 0x3f);
1250  // utf-8 encodings of values used in surrogate pairs are invalid
1251  if ((c & 0xFFFFF800) == 0xD800) return 4;
1252  *out_char = c;
1253  return 4;
1254  }
1255  *out_char = 0;
1256  return 0;
1257 }
1258 
1259 int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_text_remaining)
1260 {
1261  ImWchar* buf_out = buf;
1262  ImWchar* buf_end = buf + buf_size;
1263  while (buf_out < buf_end-1 && (!in_text_end || in_text < in_text_end) && *in_text)
1264  {
1265  unsigned int c;
1266  in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
1267  if (c == 0)
1268  break;
1269  if (c < 0x10000) // FIXME: Losing characters that don't fit in 2 bytes
1270  *buf_out++ = (ImWchar)c;
1271  }
1272  *buf_out = 0;
1273  if (in_text_remaining)
1274  *in_text_remaining = in_text;
1275  return (int)(buf_out - buf);
1276 }
1277 
1278 int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end)
1279 {
1280  int char_count = 0;
1281  while ((!in_text_end || in_text < in_text_end) && *in_text)
1282  {
1283  unsigned int c;
1284  in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
1285  if (c == 0)
1286  break;
1287  if (c < 0x10000)
1288  char_count++;
1289  }
1290  return char_count;
1291 }
1292 
1293 // Based on stb_to_utf8() from github.com/nothings/stb/
1294 static inline int ImTextCharToUtf8(char* buf, int buf_size, unsigned int c)
1295 {
1296  if (c < 0x80)
1297  {
1298  buf[0] = (char)c;
1299  return 1;
1300  }
1301  if (c < 0x800)
1302  {
1303  if (buf_size < 2) return 0;
1304  buf[0] = (char)(0xc0 + (c >> 6));
1305  buf[1] = (char)(0x80 + (c & 0x3f));
1306  return 2;
1307  }
1308  if (c >= 0xdc00 && c < 0xe000)
1309  {
1310  return 0;
1311  }
1312  if (c >= 0xd800 && c < 0xdc00)
1313  {
1314  if (buf_size < 4) return 0;
1315  buf[0] = (char)(0xf0 + (c >> 18));
1316  buf[1] = (char)(0x80 + ((c >> 12) & 0x3f));
1317  buf[2] = (char)(0x80 + ((c >> 6) & 0x3f));
1318  buf[3] = (char)(0x80 + ((c ) & 0x3f));
1319  return 4;
1320  }
1321  //else if (c < 0x10000)
1322  {
1323  if (buf_size < 3) return 0;
1324  buf[0] = (char)(0xe0 + (c >> 12));
1325  buf[1] = (char)(0x80 + ((c>> 6) & 0x3f));
1326  buf[2] = (char)(0x80 + ((c ) & 0x3f));
1327  return 3;
1328  }
1329 }
1330 
1331 static inline int ImTextCountUtf8BytesFromChar(unsigned int c)
1332 {
1333  if (c < 0x80) return 1;
1334  if (c < 0x800) return 2;
1335  if (c >= 0xdc00 && c < 0xe000) return 0;
1336  if (c >= 0xd800 && c < 0xdc00) return 4;
1337  return 3;
1338 }
1339 
1340 int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end)
1341 {
1342  char* buf_out = buf;
1343  const char* buf_end = buf + buf_size;
1344  while (buf_out < buf_end-1 && (!in_text_end || in_text < in_text_end) && *in_text)
1345  {
1346  unsigned int c = (unsigned int)(*in_text++);
1347  if (c < 0x80)
1348  *buf_out++ = (char)c;
1349  else
1350  buf_out += ImTextCharToUtf8(buf_out, (int)(buf_end-buf_out-1), c);
1351  }
1352  *buf_out = 0;
1353  return (int)(buf_out - buf);
1354 }
1355 
1356 int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end)
1357 {
1358  int bytes_count = 0;
1359  while ((!in_text_end || in_text < in_text_end) && *in_text)
1360  {
1361  unsigned int c = (unsigned int)(*in_text++);
1362  if (c < 0x80)
1363  bytes_count++;
1364  else
1365  bytes_count += ImTextCountUtf8BytesFromChar(c);
1366  }
1367  return bytes_count;
1368 }
1369 
1371 {
1372  float s = 1.0f/255.0f;
1373  return ImVec4(
1374  ((in >> IM_COL32_R_SHIFT) & 0xFF) * s,
1375  ((in >> IM_COL32_G_SHIFT) & 0xFF) * s,
1376  ((in >> IM_COL32_B_SHIFT) & 0xFF) * s,
1377  ((in >> IM_COL32_A_SHIFT) & 0xFF) * s);
1378 }
1379 
1381 {
1382  ImU32 out;
1383  out = ((ImU32)IM_F32_TO_INT8_SAT(in.x)) << IM_COL32_R_SHIFT;
1384  out |= ((ImU32)IM_F32_TO_INT8_SAT(in.y)) << IM_COL32_G_SHIFT;
1385  out |= ((ImU32)IM_F32_TO_INT8_SAT(in.z)) << IM_COL32_B_SHIFT;
1386  out |= ((ImU32)IM_F32_TO_INT8_SAT(in.w)) << IM_COL32_A_SHIFT;
1387  return out;
1388 }
1389 
1390 ImU32 ImGui::GetColorU32(ImGuiCol idx, float alpha_mul)
1391 {
1392  ImGuiStyle& style = GImGui->Style;
1393  ImVec4 c = style.Colors[idx];
1394  c.w *= style.Alpha * alpha_mul;
1395  return ColorConvertFloat4ToU32(c);
1396 }
1397 
1399 {
1400  ImGuiStyle& style = GImGui->Style;
1401  ImVec4 c = col;
1402  c.w *= style.Alpha;
1403  return ColorConvertFloat4ToU32(c);
1404 }
1405 
1407 {
1408  ImGuiStyle& style = GImGui->Style;
1409  return style.Colors[idx];
1410 }
1411 
1413 {
1414  float style_alpha = GImGui->Style.Alpha;
1415  if (style_alpha >= 1.0f)
1416  return col;
1417  ImU32 a = (col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT;
1418  a = (ImU32)(a * style_alpha); // We don't need to clamp 0..255 because Style.Alpha is in 0..1 range.
1419  return (col & ~IM_COL32_A_MASK) | (a << IM_COL32_A_SHIFT);
1420 }
1421 
1422 // Convert rgb floats ([0-1],[0-1],[0-1]) to hsv floats ([0-1],[0-1],[0-1]), from Foley & van Dam p592
1423 // Optimized http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv
1424 void ImGui::ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v)
1425 {
1426  float K = 0.f;
1427  if (g < b)
1428  {
1429  ImSwap(g, b);
1430  K = -1.f;
1431  }
1432  if (r < g)
1433  {
1434  ImSwap(r, g);
1435  K = -2.f / 6.f - K;
1436  }
1437 
1438  const float chroma = r - (g < b ? g : b);
1439  out_h = ImFabs(K + (g - b) / (6.f * chroma + 1e-20f));
1440  out_s = chroma / (r + 1e-20f);
1441  out_v = r;
1442 }
1443 
1444 // Convert hsv floats ([0-1],[0-1],[0-1]) to rgb floats ([0-1],[0-1],[0-1]), from Foley & van Dam p593
1445 // also http://en.wikipedia.org/wiki/HSL_and_HSV
1446 void ImGui::ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b)
1447 {
1448  if (s == 0.0f)
1449  {
1450  // gray
1451  out_r = out_g = out_b = v;
1452  return;
1453  }
1454 
1455  h = ImFmod(h, 1.0f) / (60.0f/360.0f);
1456  int i = (int)h;
1457  float f = h - (float)i;
1458  float p = v * (1.0f - s);
1459  float q = v * (1.0f - s * f);
1460  float t = v * (1.0f - s * (1.0f - f));
1461 
1462  switch (i)
1463  {
1464  case 0: out_r = v; out_g = t; out_b = p; break;
1465  case 1: out_r = q; out_g = v; out_b = p; break;
1466  case 2: out_r = p; out_g = v; out_b = t; break;
1467  case 3: out_r = p; out_g = q; out_b = v; break;
1468  case 4: out_r = t; out_g = p; out_b = v; break;
1469  case 5: default: out_r = v; out_g = p; out_b = q; break;
1470  }
1471 }
1472 
1473 FILE* ImFileOpen(const char* filename, const char* mode)
1474 {
1475 #if defined(_WIN32) && !defined(__CYGWIN__)
1476  // We need a fopen() wrapper because MSVC/Windows fopen doesn't handle UTF-8 filenames. Converting both strings from UTF-8 to wchar format (using a single allocation, because we can)
1477  const int filename_wsize = ImTextCountCharsFromUtf8(filename, NULL) + 1;
1478  const int mode_wsize = ImTextCountCharsFromUtf8(mode, NULL) + 1;
1480  buf.resize(filename_wsize + mode_wsize);
1481  ImTextStrFromUtf8(&buf[0], filename_wsize, filename, NULL);
1482  ImTextStrFromUtf8(&buf[filename_wsize], mode_wsize, mode, NULL);
1483  return _wfopen((wchar_t*)&buf[0], (wchar_t*)&buf[filename_wsize]);
1484 #else
1485  return fopen(filename, mode);
1486 #endif
1487 }
1488 
1489 // Load file content into memory
1490 // Memory allocated with ImGui::MemAlloc(), must be freed by user using ImGui::MemFree()
1491 void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, size_t* out_file_size, int padding_bytes)
1492 {
1493  IM_ASSERT(filename && file_open_mode);
1494  if (out_file_size)
1495  *out_file_size = 0;
1496 
1497  FILE* f;
1498  if ((f = ImFileOpen(filename, file_open_mode)) == NULL)
1499  return NULL;
1500 
1501  long file_size_signed;
1502  if (fseek(f, 0, SEEK_END) || (file_size_signed = ftell(f)) == -1 || fseek(f, 0, SEEK_SET))
1503  {
1504  fclose(f);
1505  return NULL;
1506  }
1507 
1508  size_t file_size = (size_t)file_size_signed;
1509  void* file_data = ImGui::MemAlloc(file_size + padding_bytes);
1510  if (file_data == NULL)
1511  {
1512  fclose(f);
1513  return NULL;
1514  }
1515  if (fread(file_data, 1, file_size, f) != file_size)
1516  {
1517  fclose(f);
1518  ImGui::MemFree(file_data);
1519  return NULL;
1520  }
1521  if (padding_bytes > 0)
1522  memset((void *)(((char*)file_data) + file_size), 0, (size_t)padding_bytes);
1523 
1524  fclose(f);
1525  if (out_file_size)
1526  *out_file_size = file_size;
1527 
1528  return file_data;
1529 }
1530 
1531 //-----------------------------------------------------------------------------
1532 // ImGuiStorage
1533 // Helper: Key->value storage
1534 //-----------------------------------------------------------------------------
1535 
1536 // std::lower_bound but without the bullshit
1538 {
1541  size_t count = (size_t)(last - first);
1542  while (count > 0)
1543  {
1544  size_t count2 = count >> 1;
1545  ImVector<ImGuiStorage::Pair>::iterator mid = first + count2;
1546  if (mid->key < key)
1547  {
1548  first = ++mid;
1549  count -= count2 + 1;
1550  }
1551  else
1552  {
1553  count = count2;
1554  }
1555  }
1556  return first;
1557 }
1558 
1559 // For quicker full rebuild of a storage (instead of an incremental one), you may add all your contents and then sort once.
1561 {
1562  struct StaticFunc
1563  {
1564  static int IMGUI_CDECL PairCompareByID(const void* lhs, const void* rhs)
1565  {
1566  // We can't just do a subtraction because qsort uses signed integers and subtracting our ID doesn't play well with that.
1567  if (((const Pair*)lhs)->key > ((const Pair*)rhs)->key) return +1;
1568  if (((const Pair*)lhs)->key < ((const Pair*)rhs)->key) return -1;
1569  return 0;
1570  }
1571  };
1572  if (Data.Size > 1)
1573  qsort(Data.Data, (size_t)Data.Size, sizeof(Pair), StaticFunc::PairCompareByID);
1574 }
1575 
1576 int ImGuiStorage::GetInt(ImGuiID key, int default_val) const
1577 {
1578  ImVector<Pair>::iterator it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key);
1579  if (it == Data.end() || it->key != key)
1580  return default_val;
1581  return it->val_i;
1582 }
1583 
1584 bool ImGuiStorage::GetBool(ImGuiID key, bool default_val) const
1585 {
1586  return GetInt(key, default_val ? 1 : 0) != 0;
1587 }
1588 
1589 float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const
1590 {
1591  ImVector<Pair>::iterator it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key);
1592  if (it == Data.end() || it->key != key)
1593  return default_val;
1594  return it->val_f;
1595 }
1596 
1598 {
1599  ImVector<Pair>::iterator it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key);
1600  if (it == Data.end() || it->key != key)
1601  return NULL;
1602  return it->val_p;
1603 }
1604 
1605 // References are only valid until a new value is added to the storage. Calling a Set***() function or a Get***Ref() function invalidates the pointer.
1606 int* ImGuiStorage::GetIntRef(ImGuiID key, int default_val)
1607 {
1608  ImVector<Pair>::iterator it = LowerBound(Data, key);
1609  if (it == Data.end() || it->key != key)
1610  it = Data.insert(it, Pair(key, default_val));
1611  return &it->val_i;
1612 }
1613 
1614 bool* ImGuiStorage::GetBoolRef(ImGuiID key, bool default_val)
1615 {
1616  return (bool*)GetIntRef(key, default_val ? 1 : 0);
1617 }
1618 
1619 float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val)
1620 {
1621  ImVector<Pair>::iterator it = LowerBound(Data, key);
1622  if (it == Data.end() || it->key != key)
1623  it = Data.insert(it, Pair(key, default_val));
1624  return &it->val_f;
1625 }
1626 
1627 void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val)
1628 {
1629  ImVector<Pair>::iterator it = LowerBound(Data, key);
1630  if (it == Data.end() || it->key != key)
1631  it = Data.insert(it, Pair(key, default_val));
1632  return &it->val_p;
1633 }
1634 
1635 // FIXME-OPT: Need a way to reuse the result of lower_bound when doing GetInt()/SetInt() - not too bad because it only happens on explicit interaction (maximum one a frame)
1637 {
1638  ImVector<Pair>::iterator it = LowerBound(Data, key);
1639  if (it == Data.end() || it->key != key)
1640  {
1641  Data.insert(it, Pair(key, val));
1642  return;
1643  }
1644  it->val_i = val;
1645 }
1646 
1648 {
1649  SetInt(key, val ? 1 : 0);
1650 }
1651 
1653 {
1654  ImVector<Pair>::iterator it = LowerBound(Data, key);
1655  if (it == Data.end() || it->key != key)
1656  {
1657  Data.insert(it, Pair(key, val));
1658  return;
1659  }
1660  it->val_f = val;
1661 }
1662 
1664 {
1665  ImVector<Pair>::iterator it = LowerBound(Data, key);
1666  if (it == Data.end() || it->key != key)
1667  {
1668  Data.insert(it, Pair(key, val));
1669  return;
1670  }
1671  it->val_p = val;
1672 }
1673 
1675 {
1676  for (int i = 0; i < Data.Size; i++)
1677  Data[i].val_i = v;
1678 }
1679 
1680 //-----------------------------------------------------------------------------
1681 // ImGuiTextFilter
1682 //-----------------------------------------------------------------------------
1683 
1684 // Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]"
1685 ImGuiTextFilter::ImGuiTextFilter(const char* default_filter)
1686 {
1687  if (default_filter)
1688  {
1689  ImStrncpy(InputBuf, default_filter, IM_ARRAYSIZE(InputBuf));
1690  Build();
1691  }
1692  else
1693  {
1694  InputBuf[0] = 0;
1695  CountGrep = 0;
1696  }
1697 }
1698 
1699 bool ImGuiTextFilter::Draw(const char* label, float width)
1700 {
1701  if (width != 0.0f)
1702  ImGui::PushItemWidth(width);
1703  bool value_changed = ImGui::InputText(label, InputBuf, IM_ARRAYSIZE(InputBuf));
1704  if (width != 0.0f)
1706  if (value_changed)
1707  Build();
1708  return value_changed;
1709 }
1710 
1712 {
1713  out.resize(0);
1714  const char* wb = b;
1715  const char* we = wb;
1716  while (we < e)
1717  {
1718  if (*we == separator)
1719  {
1720  out.push_back(TextRange(wb, we));
1721  wb = we + 1;
1722  }
1723  we++;
1724  }
1725  if (wb != we)
1726  out.push_back(TextRange(wb, we));
1727 }
1728 
1730 {
1731  Filters.resize(0);
1732  TextRange input_range(InputBuf, InputBuf+strlen(InputBuf));
1733  input_range.split(',', Filters);
1734 
1735  CountGrep = 0;
1736  for (int i = 0; i != Filters.Size; i++)
1737  {
1738  Filters[i].trim_blanks();
1739  if (Filters[i].empty())
1740  continue;
1741  if (Filters[i].front() != '-')
1742  CountGrep += 1;
1743  }
1744 }
1745 
1746 bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const
1747 {
1748  if (Filters.empty())
1749  return true;
1750 
1751  if (text == NULL)
1752  text = "";
1753 
1754  for (int i = 0; i != Filters.Size; i++)
1755  {
1756  const TextRange& f = Filters[i];
1757  if (f.empty())
1758  continue;
1759  if (f.front() == '-')
1760  {
1761  // Subtract
1762  if (ImStristr(text, text_end, f.begin()+1, f.end()) != NULL)
1763  return false;
1764  }
1765  else
1766  {
1767  // Grep
1768  if (ImStristr(text, text_end, f.begin(), f.end()) != NULL)
1769  return true;
1770  }
1771  }
1772 
1773  // Implicit * grep
1774  if (CountGrep == 0)
1775  return true;
1776 
1777  return false;
1778 }
1779 
1780 //-----------------------------------------------------------------------------
1781 // ImGuiTextBuffer
1782 //-----------------------------------------------------------------------------
1783 
1784 // On some platform vsnprintf() takes va_list by reference and modifies it.
1785 // va_copy is the 'correct' way to copy a va_list but Visual Studio prior to 2013 doesn't have it.
1786 #ifndef va_copy
1787 #define va_copy(dest, src) (dest = src)
1788 #endif
1789 
1790 // Helper: Text buffer for logging/accumulating text
1791 void ImGuiTextBuffer::appendfv(const char* fmt, va_list args)
1792 {
1793  va_list args_copy;
1794  va_copy(args_copy, args);
1795 
1796  int len = ImFormatStringV(NULL, 0, fmt, args); // FIXME-OPT: could do a first pass write attempt, likely successful on first pass.
1797  if (len <= 0)
1798  {
1799  va_end(args_copy);
1800  return;
1801  }
1802 
1803  const int write_off = Buf.Size;
1804  const int needed_sz = write_off + len;
1805  if (write_off + len >= Buf.Capacity)
1806  {
1807  int double_capacity = Buf.Capacity * 2;
1808  Buf.reserve(needed_sz > double_capacity ? needed_sz : double_capacity);
1809  }
1810 
1811  Buf.resize(needed_sz);
1812  ImFormatStringV(&Buf[write_off - 1], (size_t)len + 1, fmt, args_copy);
1813  va_end(args_copy);
1814 }
1815 
1816 void ImGuiTextBuffer::appendf(const char* fmt, ...)
1817 {
1818  va_list args;
1819  va_start(args, fmt);
1820  appendfv(fmt, args);
1821  va_end(args);
1822 }
1823 
1824 //-----------------------------------------------------------------------------
1825 // ImGuiSimpleColumns (internal use only)
1826 //-----------------------------------------------------------------------------
1827 
1829 {
1830  Count = 0;
1831  Spacing = Width = NextWidth = 0.0f;
1832  memset(Pos, 0, sizeof(Pos));
1833  memset(NextWidths, 0, sizeof(NextWidths));
1834 }
1835 
1836 void ImGuiMenuColumns::Update(int count, float spacing, bool clear)
1837 {
1838  IM_ASSERT(Count <= IM_ARRAYSIZE(Pos));
1839  Count = count;
1840  Width = NextWidth = 0.0f;
1841  Spacing = spacing;
1842  if (clear) memset(NextWidths, 0, sizeof(NextWidths));
1843  for (int i = 0; i < Count; i++)
1844  {
1845  if (i > 0 && NextWidths[i] > 0.0f)
1846  Width += Spacing;
1847  Pos[i] = (float)(int)Width;
1848  Width += NextWidths[i];
1849  NextWidths[i] = 0.0f;
1850  }
1851 }
1852 
1853 float ImGuiMenuColumns::DeclColumns(float w0, float w1, float w2) // not using va_arg because they promote float to double
1854 {
1855  NextWidth = 0.0f;
1856  NextWidths[0] = ImMax(NextWidths[0], w0);
1857  NextWidths[1] = ImMax(NextWidths[1], w1);
1858  NextWidths[2] = ImMax(NextWidths[2], w2);
1859  for (int i = 0; i < 3; i++)
1860  NextWidth += NextWidths[i] + ((i > 0 && NextWidths[i] > 0.0f) ? Spacing : 0.0f);
1861  return ImMax(Width, NextWidth);
1862 }
1863 
1865 {
1866  return ImMax(0.0f, avail_w - Width);
1867 }
1868 
1869 //-----------------------------------------------------------------------------
1870 // ImGuiListClipper
1871 //-----------------------------------------------------------------------------
1872 
1873 static void SetCursorPosYAndSetupDummyPrevLine(float pos_y, float line_height)
1874 {
1875  // Set cursor position and a few other things so that SetScrollHere() and Columns() can work when seeking cursor.
1876  // FIXME: It is problematic that we have to do that here, because custom/equivalent end-user code would stumble on the same issue.
1877  // The clipper should probably have a 4th step to display the last item in a regular manner.
1878  ImGui::SetCursorPosY(pos_y);
1880  window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height; // Setting those fields so that SetScrollHere() can properly function after the end of our clipper usage.
1881  window->DC.PrevLineHeight = (line_height - GImGui->Style.ItemSpacing.y); // If we end up needing more accurate data (to e.g. use SameLine) we may as well make the clipper have a fourth step to let user process and display the last item in their list.
1882  if (window->DC.ColumnsSet)
1883  window->DC.ColumnsSet->LineMinY = window->DC.CursorPos.y; // Setting this so that cell Y position are set properly
1884 }
1885 
1886 // Use case A: Begin() called from constructor with items_height<0, then called again from Sync() in StepNo 1
1887 // Use case B: Begin() called from constructor with items_height>0
1888 // FIXME-LEGACY: Ideally we should remove the Begin/End functions but they are part of the legacy API we still support. This is why some of the code in Step() calling Begin() and reassign some fields, spaghetti style.
1889 void ImGuiListClipper::Begin(int count, float items_height)
1890 {
1891  StartPosY = ImGui::GetCursorPosY();
1892  ItemsHeight = items_height;
1893  ItemsCount = count;
1894  StepNo = 0;
1895  DisplayEnd = DisplayStart = -1;
1896  if (ItemsHeight > 0.0f)
1897  {
1898  ImGui::CalcListClipping(ItemsCount, ItemsHeight, &DisplayStart, &DisplayEnd); // calculate how many to clip/display
1899  if (DisplayStart > 0)
1900  SetCursorPosYAndSetupDummyPrevLine(StartPosY + DisplayStart * ItemsHeight, ItemsHeight); // advance cursor
1901  StepNo = 2;
1902  }
1903 }
1904 
1906 {
1907  if (ItemsCount < 0)
1908  return;
1909  // In theory here we should assert that ImGui::GetCursorPosY() == StartPosY + DisplayEnd * ItemsHeight, but it feels saner to just seek at the end and not assert/crash the user.
1910  if (ItemsCount < INT_MAX)
1911  SetCursorPosYAndSetupDummyPrevLine(StartPosY + ItemsCount * ItemsHeight, ItemsHeight); // advance cursor
1912  ItemsCount = -1;
1913  StepNo = 3;
1914 }
1915 
1917 {
1918  if (ItemsCount == 0 || ImGui::GetCurrentWindowRead()->SkipItems)
1919  {
1920  ItemsCount = -1;
1921  return false;
1922  }
1923  if (StepNo == 0) // Step 0: the clipper let you process the first element, regardless of it being visible or not, so we can measure the element height.
1924  {
1925  DisplayStart = 0;
1926  DisplayEnd = 1;
1927  StartPosY = ImGui::GetCursorPosY();
1928  StepNo = 1;
1929  return true;
1930  }
1931  if (StepNo == 1) // Step 1: the clipper infer height from first element, calculate the actual range of elements to display, and position the cursor before the first element.
1932  {
1933  if (ItemsCount == 1) { ItemsCount = -1; return false; }
1934  float items_height = ImGui::GetCursorPosY() - StartPosY;
1935  IM_ASSERT(items_height > 0.0f); // If this triggers, it means Item 0 hasn't moved the cursor vertically
1936  Begin(ItemsCount-1, items_height);
1937  DisplayStart++;
1938  DisplayEnd++;
1939  StepNo = 3;
1940  return true;
1941  }
1942  if (StepNo == 2) // Step 2: dummy step only required if an explicit items_height was passed to constructor or Begin() and user still call Step(). Does nothing and switch to Step 3.
1943  {
1944  IM_ASSERT(DisplayStart >= 0 && DisplayEnd >= 0);
1945  StepNo = 3;
1946  return true;
1947  }
1948  if (StepNo == 3) // Step 3: the clipper validate that we have reached the expected Y position (corresponding to element DisplayEnd), advance the cursor to the end of the list and then returns 'false' to end the loop.
1949  End();
1950  return false;
1951 }
1952 
1953 //-----------------------------------------------------------------------------
1954 // ImGuiWindow
1955 //-----------------------------------------------------------------------------
1956 
1958  : DrawListInst(&context->DrawListSharedData)
1959 {
1960  Name = ImStrdup(name);
1961  ID = ImHash(name, 0);
1962  IDStack.push_back(ID);
1963  Flags = 0;
1964  Pos = ImVec2(0.0f, 0.0f);
1965  Size = SizeFull = ImVec2(0.0f, 0.0f);
1967  WindowPadding = ImVec2(0.0f, 0.0f);
1968  WindowRounding = 0.0f;
1969  WindowBorderSize = 0.0f;
1970  MoveId = GetID("#MOVE");
1971  ChildId = 0;
1972  Scroll = ImVec2(0.0f, 0.0f);
1973  ScrollTarget = ImVec2(FLT_MAX, FLT_MAX);
1974  ScrollTargetCenterRatio = ImVec2(0.5f, 0.5f);
1975  ScrollbarSizes = ImVec2(0.0f, 0.0f);
1976  ScrollbarX = ScrollbarY = false;
1977  Active = WasActive = false;
1978  WriteAccessed = false;
1979  Collapsed = false;
1980  CollapseToggleWanted = false;
1981  SkipItems = false;
1982  Appearing = false;
1983  CloseButton = false;
1986  BeginCount = 0;
1987  PopupId = 0;
1989  AutoFitOnlyGrows = false;
1990  AutoFitChildAxises = 0x00;
1992  HiddenFrames = 0;
1994  SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX);
1995 
1996  LastFrameActive = -1;
1997  ItemWidthDefault = 0.0f;
1998  FontWindowScale = 1.0f;
1999 
2002  ParentWindow = NULL;
2003  RootWindow = NULL;
2005  RootWindowForTabbing = NULL;
2006  RootWindowForNav = NULL;
2007 
2008  NavLastIds[0] = NavLastIds[1] = 0;
2009  NavRectRel[0] = NavRectRel[1] = ImRect();
2010  NavLastChildNavWindow = NULL;
2011 
2015 }
2016 
2018 {
2020  IM_DELETE(Name);
2021  for (int i = 0; i != ColumnsStorage.Size; i++)
2023 }
2024 
2025 ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end)
2026 {
2027  ImGuiID seed = IDStack.back();
2028  ImGuiID id = ImHash(str, str_end ? (int)(str_end - str) : 0, seed);
2029  ImGui::KeepAliveID(id);
2030  return id;
2031 }
2032 
2033 ImGuiID ImGuiWindow::GetID(const void* ptr)
2034 {
2035  ImGuiID seed = IDStack.back();
2036  ImGuiID id = ImHash(&ptr, sizeof(void*), seed);
2037  ImGui::KeepAliveID(id);
2038  return id;
2039 }
2040 
2041 ImGuiID ImGuiWindow::GetIDNoKeepAlive(const char* str, const char* str_end)
2042 {
2043  ImGuiID seed = IDStack.back();
2044  return ImHash(str, str_end ? (int)(str_end - str) : 0, seed);
2045 }
2046 
2047 // This is only used in rare/specific situations to manufacture an ID out of nowhere.
2049 {
2050  ImGuiID seed = IDStack.back();
2051  const int r_rel[4] = { (int)(r_abs.Min.x - Pos.x), (int)(r_abs.Min.y - Pos.y), (int)(r_abs.Max.x - Pos.x), (int)(r_abs.Max.y - Pos.y) };
2052  ImGuiID id = ImHash(&r_rel, sizeof(r_rel), seed);
2053  ImGui::KeepAliveID(id);
2054  return id;
2055 }
2056 
2057 //-----------------------------------------------------------------------------
2058 // Internal API exposed in imgui_internal.h
2059 //-----------------------------------------------------------------------------
2060 
2061 static void SetCurrentWindow(ImGuiWindow* window)
2062 {
2063  ImGuiContext& g = *GImGui;
2064  g.CurrentWindow = window;
2065  if (window)
2067 }
2068 
2069 static void SetNavID(ImGuiID id, int nav_layer)
2070 {
2071  ImGuiContext& g = *GImGui;
2072  IM_ASSERT(g.NavWindow);
2073  IM_ASSERT(nav_layer == 0 || nav_layer == 1);
2074  g.NavId = id;
2075  g.NavWindow->NavLastIds[nav_layer] = id;
2076 }
2077 
2078 static void SetNavIDWithRectRel(ImGuiID id, int nav_layer, const ImRect& rect_rel)
2079 {
2080  ImGuiContext& g = *GImGui;
2081  SetNavID(id, nav_layer);
2082  g.NavWindow->NavRectRel[nav_layer] = rect_rel;
2083  g.NavMousePosDirty = true;
2084  g.NavDisableHighlight = false;
2085  g.NavDisableMouseHover = true;
2086 }
2087 
2089 {
2090  ImGuiContext& g = *GImGui;
2091  g.ActiveIdIsJustActivated = (g.ActiveId != id);
2093  g.ActiveIdTimer = 0.0f;
2094  g.ActiveId = id;
2096  g.ActiveIdAllowOverlap = false;
2097  g.ActiveIdWindow = window;
2098  if (id)
2099  {
2100  g.ActiveIdIsAlive = true;
2102  }
2103 }
2104 
2106 {
2107  ImGuiContext& g = *GImGui;
2108  return g.ActiveId;
2109 }
2110 
2112 {
2113  ImGuiContext& g = *GImGui;
2114  IM_ASSERT(id != 0);
2115 
2116  // Assume that SetFocusID() is called in the context where its NavLayer is the current layer, which is the case everywhere we call it.
2117  const int nav_layer = window->DC.NavLayerCurrent;
2118  if (g.NavWindow != window)
2119  g.NavInitRequest = false;
2120  g.NavId = id;
2121  g.NavWindow = window;
2122  g.NavLayer = nav_layer;
2123  window->NavLastIds[nav_layer] = id;
2124  if (window->DC.LastItemId == id)
2125  window->NavRectRel[nav_layer] = ImRect(window->DC.LastItemRect.Min - window->Pos, window->DC.LastItemRect.Max - window->Pos);
2126 
2128  g.NavDisableMouseHover = true;
2129  else
2130  g.NavDisableHighlight = true;
2131 }
2132 
2134 {
2135  SetActiveID(0, NULL);
2136 }
2137 
2139 {
2140  ImGuiContext& g = *GImGui;
2141  g.HoveredId = id;
2142  g.HoveredIdAllowOverlap = false;
2143  g.HoveredIdTimer = (id != 0 && g.HoveredIdPreviousFrame == id) ? (g.HoveredIdTimer + g.IO.DeltaTime) : 0.0f;
2144 }
2145 
2147 {
2148  ImGuiContext& g = *GImGui;
2149  return g.HoveredId ? g.HoveredId : g.HoveredIdPreviousFrame;
2150 }
2151 
2153 {
2154  ImGuiContext& g = *GImGui;
2155  if (g.ActiveId == id)
2156  g.ActiveIdIsAlive = true;
2157 }
2158 
2159 static inline bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags)
2160 {
2161  // An active popup disable hovering on other windows (apart from its own children)
2162  // FIXME-OPT: This could be cached/stored within the window.
2163  ImGuiContext& g = *GImGui;
2164  if (g.NavWindow)
2165  if (ImGuiWindow* focused_root_window = g.NavWindow->RootWindow)
2166  if (focused_root_window->WasActive && focused_root_window != window->RootWindow)
2167  {
2168  // For the purpose of those flags we differentiate "standard popup" from "modal popup"
2169  // NB: The order of those two tests is important because Modal windows are also Popups.
2170  if (focused_root_window->Flags & ImGuiWindowFlags_Modal)
2171  return false;
2172  if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiHoveredFlags_AllowWhenBlockedByPopup))
2173  return false;
2174  }
2175 
2176  return true;
2177 }
2178 
2179 // Advance cursor given item size for layout.
2180 void ImGui::ItemSize(const ImVec2& size, float text_offset_y)
2181 {
2182  ImGuiContext& g = *GImGui;
2183  ImGuiWindow* window = g.CurrentWindow;
2184  if (window->SkipItems)
2185  return;
2186 
2187  // Always align ourselves on pixel boundaries
2188  const float line_height = ImMax(window->DC.CurrentLineHeight, size.y);
2189  const float text_base_offset = ImMax(window->DC.CurrentLineTextBaseOffset, text_offset_y);
2190  //if (g.IO.KeyAlt) window->DrawList->AddRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(size.x, line_height), IM_COL32(255,0,0,200)); // [DEBUG]
2191  window->DC.CursorPosPrevLine = ImVec2(window->DC.CursorPos.x + size.x, window->DC.CursorPos.y);
2192  window->DC.CursorPos = ImVec2((float)(int)(window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX), (float)(int)(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y));
2193  window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x);
2194  window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y - g.Style.ItemSpacing.y);
2195  //if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG]
2196 
2197  window->DC.PrevLineHeight = line_height;
2198  window->DC.PrevLineTextBaseOffset = text_base_offset;
2199  window->DC.CurrentLineHeight = window->DC.CurrentLineTextBaseOffset = 0.0f;
2200 
2201  // Horizontal layout mode
2202  if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
2203  SameLine();
2204 }
2205 
2206 void ImGui::ItemSize(const ImRect& bb, float text_offset_y)
2207 {
2208  ItemSize(bb.GetSize(), text_offset_y);
2209 }
2210 
2211 static ImGuiDir inline NavScoreItemGetQuadrant(float dx, float dy)
2212 {
2213  if (ImFabs(dx) > ImFabs(dy))
2214  return (dx > 0.0f) ? ImGuiDir_Right : ImGuiDir_Left;
2215  return (dy > 0.0f) ? ImGuiDir_Down : ImGuiDir_Up;
2216 }
2217 
2218 static float inline NavScoreItemDistInterval(float a0, float a1, float b0, float b1)
2219 {
2220  if (a1 < b0)
2221  return a1 - b0;
2222  if (b1 < a0)
2223  return a0 - b1;
2224  return 0.0f;
2225 }
2226 
2227 static void inline NavClampRectToVisibleAreaForMoveDir(ImGuiDir move_dir, ImRect& r, const ImRect& clip_rect)
2228 {
2229  if (move_dir == ImGuiDir_Left || move_dir == ImGuiDir_Right)
2230  {
2231  r.Min.y = ImClamp(r.Min.y, clip_rect.Min.y, clip_rect.Max.y);
2232  r.Max.y = ImClamp(r.Max.y, clip_rect.Min.y, clip_rect.Max.y);
2233  }
2234  else
2235  {
2236  r.Min.x = ImClamp(r.Min.x, clip_rect.Min.x, clip_rect.Max.x);
2237  r.Max.x = ImClamp(r.Max.x, clip_rect.Min.x, clip_rect.Max.x);
2238  }
2239 }
2240 
2241 // Scoring function for directional navigation. Based on https://gist.github.com/rygorous/6981057
2242 static bool NavScoreItem(ImGuiNavMoveResult* result, ImRect cand)
2243 {
2244  ImGuiContext& g = *GImGui;
2245  ImGuiWindow* window = g.CurrentWindow;
2246  if (g.NavLayer != window->DC.NavLayerCurrent)
2247  return false;
2248 
2249  const ImRect& curr = g.NavScoringRectScreen; // Current modified source rect (NB: we've applied Max.x = Min.x in NavUpdate() to inhibit the effect of having varied item width)
2250  g.NavScoringCount++;
2251 
2252  // We perform scoring on items bounding box clipped by the current clipping rectangle on the other axis (clipping on our movement axis would give us equal scores for all clipped items)
2253  // For example, this ensure that items in one column are not reached when moving vertically from items in another column.
2254  NavClampRectToVisibleAreaForMoveDir(g.NavMoveDir, cand, window->ClipRect);
2255 
2256  // Compute distance between boxes
2257  // FIXME-NAV: Introducing biases for vertical navigation, needs to be removed.
2258  float dbx = NavScoreItemDistInterval(cand.Min.x, cand.Max.x, curr.Min.x, curr.Max.x);
2259  float dby = NavScoreItemDistInterval(ImLerp(cand.Min.y, cand.Max.y, 0.2f), ImLerp(cand.Min.y, cand.Max.y, 0.8f), ImLerp(curr.Min.y, curr.Max.y, 0.2f), ImLerp(curr.Min.y, curr.Max.y, 0.8f)); // Scale down on Y to keep using box-distance for vertically touching items
2260  if (dby != 0.0f && dbx != 0.0f)
2261  dbx = (dbx/1000.0f) + ((dbx > 0.0f) ? +1.0f : -1.0f);
2262  float dist_box = ImFabs(dbx) + ImFabs(dby);
2263 
2264  // Compute distance between centers (this is off by a factor of 2, but we only compare center distances with each other so it doesn't matter)
2265  float dcx = (cand.Min.x + cand.Max.x) - (curr.Min.x + curr.Max.x);
2266  float dcy = (cand.Min.y + cand.Max.y) - (curr.Min.y + curr.Max.y);
2267  float dist_center = ImFabs(dcx) + ImFabs(dcy); // L1 metric (need this for our connectedness guarantee)
2268 
2269  // Determine which quadrant of 'curr' our candidate item 'cand' lies in based on distance
2270  ImGuiDir quadrant;
2271  float dax = 0.0f, day = 0.0f, dist_axial = 0.0f;
2272  if (dbx != 0.0f || dby != 0.0f)
2273  {
2274  // For non-overlapping boxes, use distance between boxes
2275  dax = dbx;
2276  day = dby;
2277  dist_axial = dist_box;
2278  quadrant = NavScoreItemGetQuadrant(dbx, dby);
2279  }
2280  else if (dcx != 0.0f || dcy != 0.0f)
2281  {
2282  // For overlapping boxes with different centers, use distance between centers
2283  dax = dcx;
2284  day = dcy;
2285  dist_axial = dist_center;
2286  quadrant = NavScoreItemGetQuadrant(dcx, dcy);
2287  }
2288  else
2289  {
2290  // Degenerate case: two overlapping buttons with same center, break ties arbitrarily (note that LastItemId here is really the _previous_ item order, but it doesn't matter)
2291  quadrant = (window->DC.LastItemId < g.NavId) ? ImGuiDir_Left : ImGuiDir_Right;
2292  }
2293 
2294 #if IMGUI_DEBUG_NAV_SCORING
2295  char buf[128];
2296  if (ImGui::IsMouseHoveringRect(cand.Min, cand.Max))
2297  {
2298  ImFormatString(buf, IM_ARRAYSIZE(buf), "dbox (%.2f,%.2f->%.4f)\ndcen (%.2f,%.2f->%.4f)\nd (%.2f,%.2f->%.4f)\nnav %c, quadrant %c", dbx, dby, dist_box, dcx, dcy, dist_center, dax, day, dist_axial, "WENS"[g.NavMoveDir], "WENS"[quadrant]);
2299  ImDrawList* draw_list = ImGui::GetOverlayDrawList();
2300  draw_list->AddRect(curr.Min, curr.Max, IM_COL32(255,200,0,100));
2301  draw_list->AddRect(cand.Min, cand.Max, IM_COL32(255,255,0,200));
2302  draw_list->AddRectFilled(cand.Max-ImVec2(4,4), cand.Max+ImGui::CalcTextSize(buf)+ImVec2(4,4), IM_COL32(40,0,0,150));
2303  draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Max, ~0U, buf);
2304  }
2305  else if (g.IO.KeyCtrl) // Hold to preview score in matching quadrant. Press C to rotate.
2306  {
2307  if (IsKeyPressedMap(ImGuiKey_C)) { g.NavMoveDirLast = (ImGuiDir)((g.NavMoveDirLast + 1) & 3); g.IO.KeysDownDuration[g.IO.KeyMap[ImGuiKey_C]] = 0.01f; }
2308  if (quadrant == g.NavMoveDir)
2309  {
2310  ImFormatString(buf, IM_ARRAYSIZE(buf), "%.0f/%.0f", dist_box, dist_center);
2311  ImDrawList* draw_list = ImGui::GetOverlayDrawList();
2312  draw_list->AddRectFilled(cand.Min, cand.Max, IM_COL32(255, 0, 0, 200));
2313  draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Min, IM_COL32(255, 255, 255, 255), buf);
2314  }
2315  }
2316  #endif
2317 
2318  // Is it in the quadrant we're interesting in moving to?
2319  bool new_best = false;
2320  if (quadrant == g.NavMoveDir)
2321  {
2322  // Does it beat the current best candidate?
2323  if (dist_box < result->DistBox)
2324  {
2325  result->DistBox = dist_box;
2326  result->DistCenter = dist_center;
2327  return true;
2328  }
2329  if (dist_box == result->DistBox)
2330  {
2331  // Try using distance between center points to break ties
2332  if (dist_center < result->DistCenter)
2333  {
2334  result->DistCenter = dist_center;
2335  new_best = true;
2336  }
2337  else if (dist_center == result->DistCenter)
2338  {
2339  // Still tied! we need to be extra-careful to make sure everything gets linked properly. We consistently break ties by symbolically moving "later" items
2340  // (with higher index) to the right/downwards by an infinitesimal amount since we the current "best" button already (so it must have a lower index),
2341  // this is fairly easy. This rule ensures that all buttons with dx==dy==0 will end up being linked in order of appearance along the x axis.
2342  if (((g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) ? dby : dbx) < 0.0f) // moving bj to the right/down decreases distance
2343  new_best = true;
2344  }
2345  }
2346  }
2347 
2348  // Axial check: if 'curr' has no link at all in some direction and 'cand' lies roughly in that direction, add a tentative link. This will only be kept if no "real" matches
2349  // are found, so it only augments the graph produced by the above method using extra links. (important, since it doesn't guarantee strong connectedness)
2350  // This is just to avoid buttons having no links in a particular direction when there's a suitable neighbor. you get good graphs without this too.
2351  // 2017/09/29: FIXME: This now currently only enabled inside menu bars, ideally we'd disable it everywhere. Menus in particular need to catch failure. For general navigation it feels awkward.
2352  // Disabling it may lead to disconnected graphs when nodes are very spaced out on different axis. Perhaps consider offering this as an option?
2353  if (result->DistBox == FLT_MAX && dist_axial < result->DistAxial) // Check axial match
2354  if (g.NavLayer == 1 && !(g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu))
2355  if ((g.NavMoveDir == ImGuiDir_Left && dax < 0.0f) || (g.NavMoveDir == ImGuiDir_Right && dax > 0.0f) || (g.NavMoveDir == ImGuiDir_Up && day < 0.0f) || (g.NavMoveDir == ImGuiDir_Down && day > 0.0f))
2356  {
2357  result->DistAxial = dist_axial;
2358  new_best = true;
2359  }
2360 
2361  return new_best;
2362 }
2363 
2364 static void NavSaveLastChildNavWindow(ImGuiWindow* child_window)
2365 {
2366  ImGuiWindow* parent_window = child_window;
2367  while (parent_window && (parent_window->Flags & ImGuiWindowFlags_ChildWindow) != 0 && (parent_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0)
2368  parent_window = parent_window->ParentWindow;
2369  if (parent_window && parent_window != child_window)
2370  parent_window->NavLastChildNavWindow = child_window;
2371 }
2372 
2373 // Call when we are expected to land on Layer 0 after FocusWindow()
2374 static ImGuiWindow* NavRestoreLastChildNavWindow(ImGuiWindow* window)
2375 {
2376  return window->NavLastChildNavWindow ? window->NavLastChildNavWindow : window;
2377 }
2378 
2379 static void NavRestoreLayer(int layer)
2380 {
2381  ImGuiContext& g = *GImGui;
2382  g.NavLayer = layer;
2383  if (layer == 0)
2384  g.NavWindow = NavRestoreLastChildNavWindow(g.NavWindow);
2385  if (layer == 0 && g.NavWindow->NavLastIds[0] != 0)
2386  SetNavIDWithRectRel(g.NavWindow->NavLastIds[0], layer, g.NavWindow->NavRectRel[0]);
2387  else
2389 }
2390 
2391 static inline void NavUpdateAnyRequestFlag()
2392 {
2393  ImGuiContext& g = *GImGui;
2395  if (g.NavAnyRequest)
2396  IM_ASSERT(g.NavWindow != NULL);
2397 }
2398 
2399 static bool NavMoveRequestButNoResultYet()
2400 {
2401  ImGuiContext& g = *GImGui;
2402  return g.NavMoveRequest && g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0;
2403 }
2404 
2406 {
2407  ImGuiContext& g = *GImGui;
2408  g.NavMoveRequest = false;
2409  NavUpdateAnyRequestFlag();
2410 }
2411 
2412 // We get there when either NavId == id, or when g.NavAnyRequest is set (which is updated by NavUpdateAnyRequestFlag above)
2413 static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, const ImGuiID id)
2414 {
2415  ImGuiContext& g = *GImGui;
2416  //if (!g.IO.NavActive) // [2017/10/06] Removed this possibly redundant test but I am not sure of all the side-effects yet. Some of the feature here will need to work regardless of using a _NoNavInputs flag.
2417  // return;
2418 
2419  const ImGuiItemFlags item_flags = window->DC.ItemFlags;
2420  const ImRect nav_bb_rel(nav_bb.Min - window->Pos, nav_bb.Max - window->Pos);
2421  if (g.NavInitRequest && g.NavLayer == window->DC.NavLayerCurrent)
2422  {
2423  // Even if 'ImGuiItemFlags_NoNavDefaultFocus' is on (typically collapse/close button) we record the first ResultId so they can be used as a fallback
2424  if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus) || g.NavInitResultId == 0)
2425  {
2426  g.NavInitResultId = id;
2427  g.NavInitResultRectRel = nav_bb_rel;
2428  }
2429  if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus))
2430  {
2431  g.NavInitRequest = false; // Found a match, clear request
2432  NavUpdateAnyRequestFlag();
2433  }
2434  }
2435 
2436  // Scoring for navigation
2437  // FIXME-NAV: Consider policy for double scoring (scoring from NavScoringRectScreen + scoring from a rect wrapped according to current wrapping policy)
2438  if (g.NavId != id && !(item_flags & ImGuiItemFlags_NoNav))
2439  {
2440  ImGuiNavMoveResult* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
2442  // [DEBUG] Score all items in NavWindow at all times
2443  if (!g.NavMoveRequest)
2444  g.NavMoveDir = g.NavMoveDirLast;
2445  bool new_best = NavScoreItem(result, nav_bb) && g.NavMoveRequest;
2446 #else
2447  bool new_best = g.NavMoveRequest && NavScoreItem(result, nav_bb);
2448 #endif
2449  if (new_best)
2450  {
2451  result->ID = id;
2452  result->ParentID = window->IDStack.back();
2453  result->Window = window;
2454  result->RectRel = nav_bb_rel;
2455  }
2456  }
2457 
2458  // Update window-relative bounding box of navigated item
2459  if (g.NavId == id)
2460  {
2461  g.NavWindow = window; // Always refresh g.NavWindow, because some operations such as FocusItem() don't have a window.
2462  g.NavLayer = window->DC.NavLayerCurrent;
2463  g.NavIdIsAlive = true;
2464  g.NavIdTabCounter = window->FocusIdxTabCounter;
2465  window->NavRectRel[window->DC.NavLayerCurrent] = nav_bb_rel; // Store item bounding box (relative to window position)
2466  }
2467 }
2468 
2469 // Declare item bounding box for clipping and interaction.
2470 // Note that the size can be different than the one provided to ItemSize(). Typically, widgets that spread over available surface
2471 // declare their minimum size requirement to ItemSize() and then use a larger region for drawing/interaction, which is passed to ItemAdd().
2472 bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg)
2473 {
2474  ImGuiContext& g = *GImGui;
2475  ImGuiWindow* window = g.CurrentWindow;
2476 
2477  if (id != 0)
2478  {
2479  // Navigation processing runs prior to clipping early-out
2480  // (a) So that NavInitRequest can be honored, for newly opened windows to select a default widget
2481  // (b) So that we can scroll up/down past clipped items. This adds a small O(N) cost to regular navigation requests unfortunately, but it is still limited to one window.
2482  // it may not scale very well for windows with ten of thousands of item, but at least NavMoveRequest is only set on user interaction, aka maximum once a frame.
2483  // We could early out with "if (is_clipped && !g.NavInitRequest) return false;" but when we wouldn't be able to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick)
2484  window->DC.NavLayerActiveMaskNext |= window->DC.NavLayerCurrentMask;
2485  if (g.NavId == id || g.NavAnyRequest)
2486  if (g.NavWindow->RootWindowForNav == window->RootWindowForNav)
2487  if (window == g.NavWindow || ((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened))
2488  NavProcessItem(window, nav_bb_arg ? *nav_bb_arg : bb, id);
2489  }
2490 
2491  window->DC.LastItemId = id;
2492  window->DC.LastItemRect = bb;
2493  window->DC.LastItemStatusFlags = 0;
2494 
2495  // Clipping test
2496  const bool is_clipped = IsClippedEx(bb, id, false);
2497  if (is_clipped)
2498  return false;
2499  //if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG]
2500 
2501  // We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them)
2502  if (IsMouseHoveringRect(bb.Min, bb.Max))
2504  return true;
2505 }
2506 
2507 // This is roughly matching the behavior of internal-facing ItemHoverable()
2508 // - we allow hovering to be true when ActiveId==window->MoveID, so that clicking on non-interactive items such as a Text() item still returns true with IsItemHovered()
2509 // - this should work even for non-interactive items that have no ID, so we cannot use LastItemId
2511 {
2512  ImGuiContext& g = *GImGui;
2513  ImGuiWindow* window = g.CurrentWindow;
2515  return IsItemFocused();
2516 
2517  // Test for bounding box overlap, as updated as ItemAdd()
2519  return false;
2520  IM_ASSERT((flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows)) == 0); // Flags not supported by this function
2521 
2522  // Test if we are hovering the right window (our window could be behind another window)
2523  // [2017/10/16] Reverted commit 344d48be3 and testing RootWindow instead. I believe it is correct to NOT test for RootWindow but this leaves us unable to use IsItemHovered() after EndChild() itself.
2524  // Until a solution is found I believe reverting to the test from 2017/09/27 is safe since this was the test that has been running for a long while.
2525  //if (g.HoveredWindow != window)
2526  // return false;
2528  return false;
2529 
2530  // Test if another item is active (e.g. being dragged)
2532  if (g.ActiveId != 0 && g.ActiveId != window->DC.LastItemId && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId)
2533  return false;
2534 
2535  // Test if interactions on this window are blocked by an active popup or modal
2536  if (!IsWindowContentHoverable(window, flags))
2537  return false;
2538 
2539  // Test if the item is disabled
2540  if (window->DC.ItemFlags & ImGuiItemFlags_Disabled)
2541  return false;
2542 
2543  // Special handling for the 1st item after Begin() which represent the title bar. When the window is collapsed (SkipItems==true) that last item will never be overwritten so we need to detect tht case.
2544  if (window->DC.LastItemId == window->MoveId && window->WriteAccessed)
2545  return false;
2546  return true;
2547 }
2548 
2549 // Internal facing ItemHoverable() used when submitting widgets. Differs slightly from IsItemHovered().
2551 {
2552  ImGuiContext& g = *GImGui;
2553  if (g.HoveredId != 0 && g.HoveredId != id && !g.HoveredIdAllowOverlap)
2554  return false;
2555 
2556  ImGuiWindow* window = g.CurrentWindow;
2557  if (g.HoveredWindow != window)
2558  return false;
2559  if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap)
2560  return false;
2561  if (!IsMouseHoveringRect(bb.Min, bb.Max))
2562  return false;
2563  if (g.NavDisableMouseHover || !IsWindowContentHoverable(window, ImGuiHoveredFlags_Default))
2564  return false;
2565  if (window->DC.ItemFlags & ImGuiItemFlags_Disabled)
2566  return false;
2567 
2568  SetHoveredID(id);
2569  return true;
2570 }
2571 
2572 bool ImGui::IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged)
2573 {
2574  ImGuiContext& g = *GImGui;
2575  ImGuiWindow* window = g.CurrentWindow;
2576  if (!bb.Overlaps(window->ClipRect))
2577  if (id == 0 || id != g.ActiveId)
2578  if (clip_even_when_logged || !g.LogEnabled)
2579  return true;
2580  return false;
2581 }
2582 
2583 bool ImGui::FocusableItemRegister(ImGuiWindow* window, ImGuiID id, bool tab_stop)
2584 {
2585  ImGuiContext& g = *GImGui;
2586 
2588  window->FocusIdxAllCounter++;
2589  if (allow_keyboard_focus)
2590  window->FocusIdxTabCounter++;
2591 
2592  // Process keyboard input at this point: TAB/Shift-TAB to tab out of the currently focused item.
2593  // Note that we can always TAB out of a widget that doesn't allow tabbing in.
2594  if (tab_stop && (g.ActiveId == id) && window->FocusIdxAllRequestNext == INT_MAX && window->FocusIdxTabRequestNext == INT_MAX && !g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab))
2595  window->FocusIdxTabRequestNext = window->FocusIdxTabCounter + (g.IO.KeyShift ? (allow_keyboard_focus ? -1 : 0) : +1); // Modulo on index will be applied at the end of frame once we've got the total counter of items.
2596 
2597  if (window->FocusIdxAllCounter == window->FocusIdxAllRequestCurrent)
2598  return true;
2599  if (allow_keyboard_focus && window->FocusIdxTabCounter == window->FocusIdxTabRequestCurrent)
2600  {
2601  g.NavJustTabbedId = id;
2602  return true;
2603  }
2604 
2605  return false;
2606 }
2607 
2609 {
2610  window->FocusIdxAllCounter--;
2611  window->FocusIdxTabCounter--;
2612 }
2613 
2614 ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_x, float default_y)
2615 {
2616  ImGuiContext& g = *GImGui;
2617  ImVec2 content_max;
2618  if (size.x < 0.0f || size.y < 0.0f)
2619  content_max = g.CurrentWindow->Pos + GetContentRegionMax();
2620  if (size.x <= 0.0f)
2621  size.x = (size.x == 0.0f) ? default_x : ImMax(content_max.x - g.CurrentWindow->DC.CursorPos.x, 4.0f) + size.x;
2622  if (size.y <= 0.0f)
2623  size.y = (size.y == 0.0f) ? default_y : ImMax(content_max.y - g.CurrentWindow->DC.CursorPos.y, 4.0f) + size.y;
2624  return size;
2625 }
2626 
2627 float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x)
2628 {
2629  if (wrap_pos_x < 0.0f)
2630  return 0.0f;
2631 
2632  ImGuiWindow* window = GetCurrentWindowRead();
2633  if (wrap_pos_x == 0.0f)
2634  wrap_pos_x = GetContentRegionMax().x + window->Pos.x;
2635  else if (wrap_pos_x > 0.0f)
2636  wrap_pos_x += window->Pos.x - window->Scroll.x; // wrap_pos_x is provided is window local space
2637 
2638  return ImMax(wrap_pos_x - pos.x, 1.0f);
2639 }
2640 
2641 //-----------------------------------------------------------------------------
2642 
2643 void* ImGui::MemAlloc(size_t size)
2644 {
2645  GImAllocatorActiveAllocationsCount++;
2646  return GImAllocatorAllocFunc(size, GImAllocatorUserData);
2647 }
2648 
2649 void ImGui::MemFree(void* ptr)
2650 {
2651  if (ptr) GImAllocatorActiveAllocationsCount--;
2652  return GImAllocatorFreeFunc(ptr, GImAllocatorUserData);
2653 }
2654 
2656 {
2657  return GImGui->IO.GetClipboardTextFn ? GImGui->IO.GetClipboardTextFn(GImGui->IO.ClipboardUserData) : "";
2658 }
2659 
2660 void ImGui::SetClipboardText(const char* text)
2661 {
2662  if (GImGui->IO.SetClipboardTextFn)
2663  GImGui->IO.SetClipboardTextFn(GImGui->IO.ClipboardUserData, text);
2664 }
2665 
2666 const char* ImGui::GetVersion()
2667 {
2668  return IMGUI_VERSION;
2669 }
2670 
2671 // Internal state access - if you want to share ImGui state between modules (e.g. DLL) or allocate it yourself
2672 // Note that we still point to some static data and members (such as GFontAtlas), so the state instance you end up using will point to the static data within its module
2674 {
2675  return GImGui;
2676 }
2677 
2679 {
2680 #ifdef IMGUI_SET_CURRENT_CONTEXT_FUNC
2681  IMGUI_SET_CURRENT_CONTEXT_FUNC(ctx); // For custom thread-based hackery you may want to have control over this.
2682 #else
2683  GImGui = ctx;
2684 #endif
2685 }
2686 
2687 // Helper function to verify that the type sizes are matching between the calling file's compilation unit and imgui.cpp's compilation unit
2688 // If the user has inconsistent compilation settings, imgui configuration #define, packing pragma, etc. you may see different structures from what imgui.cpp sees which is highly problematic.
2689 bool ImGui::DebugCheckVersionAndDataLayout(const char* version, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_vert)
2690 {
2691  bool error = false;
2692  if (strcmp(version, IMGUI_VERSION)!=0) { error = true; IM_ASSERT(strcmp(version,IMGUI_VERSION)==0 && "Mismatch version string!"); }
2693  if (sz_io != sizeof(ImGuiIO)) { error = true; IM_ASSERT(sz_io == sizeof(ImGuiIO) && "Mismatched struct layout!"); }
2694  if (sz_style != sizeof(ImGuiStyle)) { error = true; IM_ASSERT(sz_style == sizeof(ImGuiStyle) && "Mismatched struct layout!"); }
2695  if (sz_vec2 != sizeof(ImVec2)) { error = true; IM_ASSERT(sz_vec2 == sizeof(ImVec2) && "Mismatched struct layout!"); }
2696  if (sz_vec4 != sizeof(ImVec4)) { error = true; IM_ASSERT(sz_vec4 == sizeof(ImVec4) && "Mismatched struct layout!"); }
2697  if (sz_vert != sizeof(ImDrawVert)) { error = true; IM_ASSERT(sz_vert == sizeof(ImDrawVert) && "Mismatched struct layout!"); }
2698  return !error;
2699 }
2700 
2701 void ImGui::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void(*free_func)(void* ptr, void* user_data), void* user_data)
2702 {
2703  GImAllocatorAllocFunc = alloc_func;
2704  GImAllocatorFreeFunc = free_func;
2705  GImAllocatorUserData = user_data;
2706 }
2707 
2709 {
2710  ImGuiContext* ctx = IM_NEW(ImGuiContext)(shared_font_atlas);
2711  if (GImGui == NULL)
2712  SetCurrentContext(ctx);
2713  Initialize(ctx);
2714  return ctx;
2715 }
2716 
2718 {
2719  if (ctx == NULL)
2720  ctx = GImGui;
2721  Shutdown(ctx);
2722  if (GImGui == ctx)
2723  SetCurrentContext(NULL);
2724  IM_DELETE(ctx);
2725 }
2726 
2728 {
2729  IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() or ImGui::SetCurrentContext()?");
2730  return GImGui->IO;
2731 }
2732 
2734 {
2735  IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() or ImGui::SetCurrentContext()?");
2736  return GImGui->Style;
2737 }
2738 
2739 // Same value as passed to the old io.RenderDrawListsFn function. Valid after Render() and until the next call to NewFrame()
2741 {
2742  ImGuiContext& g = *GImGui;
2743  return g.DrawData.Valid ? &g.DrawData : NULL;
2744 }
2745 
2747 {
2748  return GImGui->Time;
2749 }
2750 
2752 {
2753  return GImGui->FrameCount;
2754 }
2755 
2757 {
2758  return &GImGui->OverlayDrawList;
2759 }
2760 
2762 {
2763  return &GImGui->DrawListSharedData;
2764 }
2765 
2766 // This needs to be called before we submit any widget (aka in or before Begin)
2767 void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit)
2768 {
2769  ImGuiContext& g = *GImGui;
2770  IM_ASSERT(window == g.NavWindow);
2771  bool init_for_nav = false;
2772  if (!(window->Flags & ImGuiWindowFlags_NoNavInputs))
2773  if (!(window->Flags & ImGuiWindowFlags_ChildWindow) || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastIds[0] == 0) || force_reinit)
2774  init_for_nav = true;
2775  if (init_for_nav)
2776  {
2777  SetNavID(0, g.NavLayer);
2778  g.NavInitRequest = true;
2779  g.NavInitRequestFromMove = false;
2780  g.NavInitResultId = 0;
2782  NavUpdateAnyRequestFlag();
2783  }
2784  else
2785  {
2786  g.NavId = window->NavLastIds[0];
2787  }
2788 }
2789 
2790 static ImVec2 NavCalcPreferredRefPos()
2791 {
2792  ImGuiContext& g = *GImGui;
2794  return ImFloor(g.IO.MousePos);
2795 
2796  // When navigation is active and mouse is disabled, decide on an arbitrary position around the bottom left of the currently navigated item
2797  const ImRect& rect_rel = g.NavWindow->NavRectRel[g.NavLayer];
2798  ImVec2 pos = g.NavWindow->Pos + ImVec2(rect_rel.Min.x + ImMin(g.Style.FramePadding.x*4, rect_rel.GetWidth()), rect_rel.Max.y - ImMin(g.Style.FramePadding.y, rect_rel.GetHeight()));
2799  ImRect visible_rect = GetViewportRect();
2800  return ImFloor(ImClamp(pos, visible_rect.Min, visible_rect.Max)); // ImFloor() is important because non-integer mouse position application in back-end might be lossy and result in undesirable non-zero delta.
2801 }
2802 
2803 static int FindWindowIndex(ImGuiWindow* window) // FIXME-OPT O(N)
2804 {
2805  ImGuiContext& g = *GImGui;
2806  for (int i = g.Windows.Size-1; i >= 0; i--)
2807  if (g.Windows[i] == window)
2808  return i;
2809  return -1;
2810 }
2811 
2812 static ImGuiWindow* FindWindowNavigable(int i_start, int i_stop, int dir) // FIXME-OPT O(N)
2813 {
2814  ImGuiContext& g = *GImGui;
2815  for (int i = i_start; i >= 0 && i < g.Windows.Size && i != i_stop; i += dir)
2817  return g.Windows[i];
2818  return NULL;
2819 }
2820 
2822 {
2823  ImGuiContext& g = *GImGui;
2824  if (mode == ImGuiInputReadMode_Down)
2825  return g.IO.NavInputs[n]; // Instant, read analog input (0.0f..1.0f, as provided by user)
2826 
2827  const float t = g.IO.NavInputsDownDuration[n];
2828  if (t < 0.0f && mode == ImGuiInputReadMode_Released) // Return 1.0f when just released, no repeat, ignore analog input.
2829  return (g.IO.NavInputsDownDurationPrev[n] >= 0.0f ? 1.0f : 0.0f);
2830  if (t < 0.0f)
2831  return 0.0f;
2832  if (mode == ImGuiInputReadMode_Pressed) // Return 1.0f when just pressed, no repeat, ignore analog input.
2833  return (t == 0.0f) ? 1.0f : 0.0f;
2834  if (mode == ImGuiInputReadMode_Repeat)
2835  return (float)CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, g.IO.KeyRepeatDelay * 0.80f, g.IO.KeyRepeatRate * 0.80f);
2836  if (mode == ImGuiInputReadMode_RepeatSlow)
2837  return (float)CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, g.IO.KeyRepeatDelay * 1.00f, g.IO.KeyRepeatRate * 2.00f);
2838  if (mode == ImGuiInputReadMode_RepeatFast)
2839  return (float)CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, g.IO.KeyRepeatDelay * 0.80f, g.IO.KeyRepeatRate * 0.30f);
2840  return 0.0f;
2841 }
2842 
2843 // Equivalent of IsKeyDown() for NavInputs[]
2844 static bool IsNavInputDown(ImGuiNavInput n)
2845 {
2846  return GImGui->IO.NavInputs[n] > 0.0f;
2847 }
2848 
2849 // Equivalent of IsKeyPressed() for NavInputs[]
2850 static bool IsNavInputPressed(ImGuiNavInput n, ImGuiInputReadMode mode)
2851 {
2852  return ImGui::GetNavInputAmount(n, mode) > 0.0f;
2853 }
2854 
2855 static bool IsNavInputPressedAnyOfTwo(ImGuiNavInput n1, ImGuiNavInput n2, ImGuiInputReadMode mode)
2856 {
2857  return (ImGui::GetNavInputAmount(n1, mode) + ImGui::GetNavInputAmount(n2, mode)) > 0.0f;
2858 }
2859 
2860 ImVec2 ImGui::GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor, float fast_factor)
2861 {
2862  ImVec2 delta(0.0f, 0.0f);
2863  if (dir_sources & ImGuiNavDirSourceFlags_Keyboard)
2865  if (dir_sources & ImGuiNavDirSourceFlags_PadDPad)
2867  if (dir_sources & ImGuiNavDirSourceFlags_PadLStick)
2869  if (slow_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakSlow))
2870  delta *= slow_factor;
2871  if (fast_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakFast))
2872  delta *= fast_factor;
2873  return delta;
2874 }
2875 
2876 static void NavUpdateWindowingHighlightWindow(int focus_change_dir)
2877 {
2878  ImGuiContext& g = *GImGui;
2881  return;
2882 
2883  const int i_current = FindWindowIndex(g.NavWindowingTarget);
2884  ImGuiWindow* window_target = FindWindowNavigable(i_current + focus_change_dir, -INT_MAX, focus_change_dir);
2885  if (!window_target)
2886  window_target = FindWindowNavigable((focus_change_dir < 0) ? (g.Windows.Size - 1) : 0, i_current, focus_change_dir);
2887  g.NavWindowingTarget = window_target;
2888  g.NavWindowingToggleLayer = false;
2889 }
2890 
2891 // Window management mode (hold to: change focus/move/resize, tap to: toggle menu layer)
2892 static void ImGui::NavUpdateWindowing()
2893 {
2894  ImGuiContext& g = *GImGui;
2895  ImGuiWindow* apply_focus_window = NULL;
2896  bool apply_toggle_layer = false;
2897 
2898  bool start_windowing_with_gamepad = !g.NavWindowingTarget && IsNavInputPressed(ImGuiNavInput_Menu, ImGuiInputReadMode_Pressed);
2899  bool start_windowing_with_keyboard = !g.NavWindowingTarget && g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab) && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard);
2900  if (start_windowing_with_gamepad || start_windowing_with_keyboard)
2901  if (ImGuiWindow* window = g.NavWindow ? g.NavWindow : FindWindowNavigable(g.Windows.Size - 1, -INT_MAX, -1))
2902  {
2905  g.NavWindowingToggleLayer = start_windowing_with_keyboard ? false : true;
2906  g.NavInputSource = start_windowing_with_keyboard ? ImGuiInputSource_NavKeyboard : ImGuiInputSource_NavGamepad;
2907  }
2908 
2909  // Gamepad update
2912  {
2913  // Highlight only appears after a brief time holding the button, so that a fast tap on PadMenu (to toggle NavLayer) doesn't add visual noise
2914  g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingHighlightTimer - 0.20f) / 0.05f));
2915 
2916  // Select window to focus
2917  const int focus_change_dir = (int)IsNavInputPressed(ImGuiNavInput_FocusPrev, ImGuiInputReadMode_RepeatSlow) - (int)IsNavInputPressed(ImGuiNavInput_FocusNext, ImGuiInputReadMode_RepeatSlow);
2918  if (focus_change_dir != 0)
2919  {
2920  NavUpdateWindowingHighlightWindow(focus_change_dir);
2921  g.NavWindowingHighlightAlpha = 1.0f;
2922  }
2923 
2924  // Single press toggles NavLayer, long press with L/R apply actual focus on release (until then the window was merely rendered front-most)
2925  if (!IsNavInputDown(ImGuiNavInput_Menu))
2926  {
2927  g.NavWindowingToggleLayer &= (g.NavWindowingHighlightAlpha < 1.0f); // Once button was held long enough we don't consider it a tap-to-toggle-layer press anymore.
2929  apply_toggle_layer = true;
2930  else if (!g.NavWindowingToggleLayer)
2931  apply_focus_window = g.NavWindowingTarget;
2932  g.NavWindowingTarget = NULL;
2933  }
2934  }
2935 
2936  // Keyboard: Focus
2938  {
2939  // Visuals only appears after a brief time after pressing TAB the first time, so that a fast CTRL+TAB doesn't add visual noise
2940  g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingHighlightTimer - 0.15f) / 0.04f)); // 1.0f
2941  if (IsKeyPressedMap(ImGuiKey_Tab, true))
2942  NavUpdateWindowingHighlightWindow(g.IO.KeyShift ? +1 : -1);
2943  if (!g.IO.KeyCtrl)
2944  apply_focus_window = g.NavWindowingTarget;
2945  }
2946 
2947  // Keyboard: Press and Release ALT to toggle menu layer
2948  // FIXME: We lack an explicit IO variable for "is the imgui window focused", so compare mouse validity to detect the common case of back-end clearing releases all keys on ALT-TAB
2949  if ((g.ActiveId == 0 || g.ActiveIdAllowOverlap) && IsNavInputPressed(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Released))
2951  apply_toggle_layer = true;
2952 
2953  // Move window
2955  {
2956  ImVec2 move_delta;
2961  if (move_delta.x != 0.0f || move_delta.y != 0.0f)
2962  {
2963  const float NAV_MOVE_SPEED = 800.0f;
2964  const float move_speed = ImFloor(NAV_MOVE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y)); // FIXME: Doesn't code variable framerate very well
2965  g.NavWindowingTarget->Pos += move_delta * move_speed;
2966  g.NavDisableMouseHover = true;
2968  }
2969  }
2970 
2971  // Apply final focus
2972  if (apply_focus_window && (g.NavWindow == NULL || apply_focus_window != g.NavWindow->RootWindowForTabbing))
2973  {
2974  g.NavDisableHighlight = false;
2975  g.NavDisableMouseHover = true;
2976  apply_focus_window = NavRestoreLastChildNavWindow(apply_focus_window);
2977  ClosePopupsOverWindow(apply_focus_window);
2978  FocusWindow(apply_focus_window);
2979  if (apply_focus_window->NavLastIds[0] == 0)
2980  NavInitWindow(apply_focus_window, false);
2981 
2982  // If the window only has a menu layer, select it directly
2983  if (apply_focus_window->DC.NavLayerActiveMask == (1 << 1))
2984  g.NavLayer = 1;
2985  }
2986  if (apply_focus_window)
2987  g.NavWindowingTarget = NULL;
2988 
2989  // Apply menu/layer toggle
2990  if (apply_toggle_layer && g.NavWindow)
2991  {
2992  ImGuiWindow* new_nav_window = g.NavWindow;
2993  while ((new_nav_window->DC.NavLayerActiveMask & (1 << 1)) == 0 && (new_nav_window->Flags & ImGuiWindowFlags_ChildWindow) != 0 && (new_nav_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0)
2994  new_nav_window = new_nav_window->ParentWindow;
2995  if (new_nav_window != g.NavWindow)
2996  {
2997  ImGuiWindow* old_nav_window = g.NavWindow;
2998  FocusWindow(new_nav_window);
2999  new_nav_window->NavLastChildNavWindow = old_nav_window;
3000  }
3001  g.NavDisableHighlight = false;
3002  g.NavDisableMouseHover = true;
3003  NavRestoreLayer((g.NavWindow->DC.NavLayerActiveMask & (1 << 1)) ? (g.NavLayer ^ 1) : 0);
3004  }
3005 }
3006 
3007 // NB: We modify rect_rel by the amount we scrolled for, so it is immediately updated.
3008 static void NavScrollToBringItemIntoView(ImGuiWindow* window, ImRect& item_rect_rel)
3009 {
3010  // Scroll to keep newly navigated item fully into view
3011  ImRect window_rect_rel(window->InnerMainRect.Min - window->Pos - ImVec2(1, 1), window->InnerMainRect.Max - window->Pos + ImVec2(1, 1));
3012  //g.OverlayDrawList.AddRect(window->Pos + window_rect_rel.Min, window->Pos + window_rect_rel.Max, IM_COL32_WHITE); // [DEBUG]
3013  if (window_rect_rel.Contains(item_rect_rel))
3014  return;
3015 
3016  ImGuiContext& g = *GImGui;
3017  if (window->ScrollbarX && item_rect_rel.Min.x < window_rect_rel.Min.x)
3018  {
3019  window->ScrollTarget.x = item_rect_rel.Min.x + window->Scroll.x - g.Style.ItemSpacing.x;
3020  window->ScrollTargetCenterRatio.x = 0.0f;
3021  }
3022  else if (window->ScrollbarX && item_rect_rel.Max.x >= window_rect_rel.Max.x)
3023  {
3024  window->ScrollTarget.x = item_rect_rel.Max.x + window->Scroll.x + g.Style.ItemSpacing.x;
3025  window->ScrollTargetCenterRatio.x = 1.0f;
3026  }
3027  if (item_rect_rel.Min.y < window_rect_rel.Min.y)
3028  {
3029  window->ScrollTarget.y = item_rect_rel.Min.y + window->Scroll.y - g.Style.ItemSpacing.y;
3030  window->ScrollTargetCenterRatio.y = 0.0f;
3031  }
3032  else if (item_rect_rel.Max.y >= window_rect_rel.Max.y)
3033  {
3034  window->ScrollTarget.y = item_rect_rel.Max.y + window->Scroll.y + g.Style.ItemSpacing.y;
3035  window->ScrollTargetCenterRatio.y = 1.0f;
3036  }
3037 
3038  // Estimate upcoming scroll so we can offset our relative mouse position so mouse position can be applied immediately after in NavUpdate()
3039  ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window, false);
3040  item_rect_rel.Translate(window->Scroll - next_scroll);
3041 }
3042 
3043 static void ImGui::NavUpdate()
3044 {
3045  ImGuiContext& g = *GImGui;
3046  g.IO.WantSetMousePos = false;
3047 
3048 #if 0
3049  if (g.NavScoringCount > 0) printf("[%05d] NavScoringCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.FrameCount, g.NavScoringCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest);
3050 #endif
3051 
3055 
3056  // Update Keyboard->Nav inputs mapping
3058  {
3059  #define NAV_MAP_KEY(_KEY, _NAV_INPUT) if (IsKeyDown(g.IO.KeyMap[_KEY])) { g.IO.NavInputs[_NAV_INPUT] = 1.0f; g.NavInputSource = ImGuiInputSource_NavKeyboard; }
3067  if (g.IO.KeyCtrl) g.IO.NavInputs[ImGuiNavInput_TweakSlow] = 1.0f;
3068  if (g.IO.KeyShift) g.IO.NavInputs[ImGuiNavInput_TweakFast] = 1.0f;
3069  if (g.IO.KeyAlt) g.IO.NavInputs[ImGuiNavInput_KeyMenu_] = 1.0f;
3070  #undef NAV_MAP_KEY
3071  }
3072 
3074  for (int i = 0; i < IM_ARRAYSIZE(g.IO.NavInputs); i++)
3075  g.IO.NavInputsDownDuration[i] = (g.IO.NavInputs[i] > 0.0f) ? (g.IO.NavInputsDownDuration[i] < 0.0f ? 0.0f : g.IO.NavInputsDownDuration[i] + g.IO.DeltaTime) : -1.0f;
3076 
3077  // Process navigation init request (select first/default focus)
3079  {
3080  // Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called)
3081  IM_ASSERT(g.NavWindow);
3082  if (g.NavInitRequestFromMove)
3083  SetNavIDWithRectRel(g.NavInitResultId, g.NavLayer, g.NavInitResultRectRel);
3084  else
3085  SetNavID(g.NavInitResultId, g.NavLayer);
3087  }
3088  g.NavInitRequest = false;
3089  g.NavInitRequestFromMove = false;
3090  g.NavInitResultId = 0;
3091  g.NavJustMovedToId = 0;
3092 
3093  // Process navigation move request
3094  if (g.NavMoveRequest && (g.NavMoveResultLocal.ID != 0 || g.NavMoveResultOther.ID != 0))
3095  {
3096  // Select which result to use
3098  if (g.NavMoveResultOther.ID != 0 && g.NavMoveResultOther.Window->ParentWindow == g.NavWindow) // Maybe entering a flattened child? In this case solve the tie using the regular scoring rules
3100  result = &g.NavMoveResultOther;
3101 
3102  IM_ASSERT(g.NavWindow && result->Window);
3103 
3104  // Scroll to keep newly navigated item fully into view
3105  if (g.NavLayer == 0)
3106  NavScrollToBringItemIntoView(result->Window, result->RectRel);
3107 
3108  // Apply result from previous frame navigation directional move request
3109  ClearActiveID();
3110  g.NavWindow = result->Window;
3111  SetNavIDWithRectRel(result->ID, g.NavLayer, result->RectRel);
3112  g.NavJustMovedToId = result->ID;
3113  g.NavMoveFromClampedRefRect = false;
3114  }
3115 
3116  // When a forwarded move request failed, we restore the highlight that we disabled during the forward frame
3118  {
3120  if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0)
3121  g.NavDisableHighlight = false;
3123  }
3124 
3125  // Apply application mouse position movement, after we had a chance to process move request result.
3126  if (g.NavMousePosDirty && g.NavIdIsAlive)
3127  {
3128  // Set mouse position given our knowledge of the navigated item position from last frame
3130  {
3132  g.IO.MousePos = g.IO.MousePosPrev = NavCalcPreferredRefPos();
3133  g.IO.WantSetMousePos = true;
3134  }
3135  g.NavMousePosDirty = false;
3136  }
3137  g.NavIdIsAlive = false;
3138  g.NavJustTabbedId = 0;
3139  IM_ASSERT(g.NavLayer == 0 || g.NavLayer == 1);
3140 
3141  // Store our return window (for returning from Layer 1 to Layer 0) and clear it as soon as we step back in our own Layer 0
3142  if (g.NavWindow)
3143  NavSaveLastChildNavWindow(g.NavWindow);
3144  if (g.NavWindow && g.NavWindow->NavLastChildNavWindow != NULL && g.NavLayer == 0)
3145  g.NavWindow->NavLastChildNavWindow = NULL;
3146 
3147  NavUpdateWindowing();
3148 
3149  // Set output flags for user application
3150  bool nav_keyboard_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
3151  bool nav_gamepad_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (g.IO.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;
3152  g.IO.NavActive = (nav_keyboard_active || nav_gamepad_active) && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs);
3153  g.IO.NavVisible = (g.IO.NavActive && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL) || g.NavInitRequest;
3154 
3155  // Process NavCancel input (to close a popup, get back to parent, clear focus)
3156  if (IsNavInputPressed(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed))
3157  {
3158  if (g.ActiveId != 0)
3159  {
3160  ClearActiveID();
3161  }
3163  {
3164  // Exit child window
3165  ImGuiWindow* child_window = g.NavWindow;
3166  ImGuiWindow* parent_window = g.NavWindow->ParentWindow;
3167  IM_ASSERT(child_window->ChildId != 0);
3168  FocusWindow(parent_window);
3169  SetNavID(child_window->ChildId, 0);
3170  g.NavIdIsAlive = false;
3171  if (g.NavDisableMouseHover)
3172  g.NavMousePosDirty = true;
3173  }
3174  else if (g.OpenPopupStack.Size > 0)
3175  {
3176  // Close open popup/menu
3178  ClosePopupToLevel(g.OpenPopupStack.Size - 1);
3179  }
3180  else if (g.NavLayer != 0)
3181  {
3182  // Leave the "menu" layer
3183  NavRestoreLayer(0);
3184  }
3185  else
3186  {
3187  // Clear NavLastId for popups but keep it for regular child window so we can leave one and come back where we were
3189  g.NavWindow->NavLastIds[0] = 0;
3190  g.NavId = 0;
3191  }
3192  }
3193 
3194  // Process manual activation request
3197  {
3198  bool activate_down = IsNavInputDown(ImGuiNavInput_Activate);
3199  bool activate_pressed = activate_down && IsNavInputPressed(ImGuiNavInput_Activate, ImGuiInputReadMode_Pressed);
3200  if (g.ActiveId == 0 && activate_pressed)
3201  g.NavActivateId = g.NavId;
3202  if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_down)
3203  g.NavActivateDownId = g.NavId;
3204  if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_pressed)
3206  if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && IsNavInputPressed(ImGuiNavInput_Input, ImGuiInputReadMode_Pressed))
3207  g.NavInputId = g.NavId;
3208  }
3210  g.NavDisableHighlight = true;
3211  if (g.NavActivateId != 0)
3213  g.NavMoveRequest = false;
3214 
3215  // Process programmatic activation request
3216  if (g.NavNextActivateId != 0)
3218  g.NavNextActivateId = 0;
3219 
3220  // Initiate directional inputs request
3221  const int allowed_dir_flags = (g.ActiveId == 0) ? ~0 : g.ActiveIdAllowNavDirFlags;
3223  {
3225  if (g.NavWindow && !g.NavWindowingTarget && allowed_dir_flags && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
3226  {
3227  if ((allowed_dir_flags & (1<<ImGuiDir_Left)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadLeft, ImGuiNavInput_KeyLeft_, ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Left;
3228  if ((allowed_dir_flags & (1<<ImGuiDir_Right)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadRight,ImGuiNavInput_KeyRight_,ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Right;
3229  if ((allowed_dir_flags & (1<<ImGuiDir_Up)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadUp, ImGuiNavInput_KeyUp_, ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Up;
3230  if ((allowed_dir_flags & (1<<ImGuiDir_Down)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadDown, ImGuiNavInput_KeyDown_, ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Down;
3231  }
3232  }
3233  else
3234  {
3235  // Forwarding previous request (which has been modified, e.g. wrap around menus rewrite the requests with a starting rectangle at the other side of the window)
3239  }
3240 
3241  if (g.NavMoveDir != ImGuiDir_None)
3242  {
3243  g.NavMoveRequest = true;
3244  g.NavMoveDirLast = g.NavMoveDir;
3245  }
3246 
3247  // If we initiate a movement request and have no current NavId, we initiate a InitDefautRequest that will be used as a fallback if the direction fails to find a match
3248  if (g.NavMoveRequest && g.NavId == 0)
3249  {
3251  g.NavInitResultId = 0;
3252  g.NavDisableHighlight = false;
3253  }
3254 
3255  NavUpdateAnyRequestFlag();
3256 
3257  // Scrolling
3259  {
3260  // *Fallback* manual-scroll with NavUp/NavDown when window has no navigable item
3261  ImGuiWindow* window = g.NavWindow;
3262  const float scroll_speed = ImFloor(window->CalcFontSize() * 100 * g.IO.DeltaTime + 0.5f); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported.
3263  if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest)
3264  {
3266  SetWindowScrollX(window, ImFloor(window->Scroll.x + ((g.NavMoveDir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed));
3268  SetWindowScrollY(window, ImFloor(window->Scroll.y + ((g.NavMoveDir == ImGuiDir_Up) ? -1.0f : +1.0f) * scroll_speed));
3269  }
3270 
3271  // *Normal* Manual scroll with NavScrollXXX keys
3272  // Next movement request will clamp the NavId reference rectangle to the visible area, so navigation will resume within those bounds.
3274  if (scroll_dir.x != 0.0f && window->ScrollbarX)
3275  {
3276  SetWindowScrollX(window, ImFloor(window->Scroll.x + scroll_dir.x * scroll_speed));
3277  g.NavMoveFromClampedRefRect = true;
3278  }
3279  if (scroll_dir.y != 0.0f)
3280  {
3281  SetWindowScrollY(window, ImFloor(window->Scroll.y + scroll_dir.y * scroll_speed));
3282  g.NavMoveFromClampedRefRect = true;
3283  }
3284  }
3285 
3286  // Reset search results
3289 
3290  // When we have manually scrolled (without using navigation) and NavId becomes out of bounds, we project its bounding box to the visible area to restart navigation within visible items
3291  if (g.NavMoveRequest && g.NavMoveFromClampedRefRect && g.NavLayer == 0)
3292  {
3293  ImGuiWindow* window = g.NavWindow;
3294  ImRect window_rect_rel(window->InnerMainRect.Min - window->Pos - ImVec2(1,1), window->InnerMainRect.Max - window->Pos + ImVec2(1,1));
3295  if (!window_rect_rel.Contains(window->NavRectRel[g.NavLayer]))
3296  {
3297  float pad = window->CalcFontSize() * 0.5f;
3298  window_rect_rel.Expand(ImVec2(-ImMin(window_rect_rel.GetWidth(), pad), -ImMin(window_rect_rel.GetHeight(), pad))); // Terrible approximation for the intent of starting navigation from first fully visible item
3299  window->NavRectRel[g.NavLayer].ClipWith(window_rect_rel);
3300  g.NavId = 0;
3301  }
3302  g.NavMoveFromClampedRefRect = false;
3303  }
3304 
3305  // For scoring we use a single segment on the left side our current item bounding box (not touching the edge to avoid box overlap with zero-spaced items)
3306  ImRect nav_rect_rel = (g.NavWindow && !g.NavWindow->NavRectRel[g.NavLayer].IsInverted()) ? g.NavWindow->NavRectRel[g.NavLayer] : ImRect(0,0,0,0);
3307  g.NavScoringRectScreen = g.NavWindow ? ImRect(g.NavWindow->Pos + nav_rect_rel.Min, g.NavWindow->Pos + nav_rect_rel.Max) : GetViewportRect();
3310  IM_ASSERT(!g.NavScoringRectScreen.IsInverted()); // Ensure if we have a finite, non-inverted bounding box here will allows us to remove extraneous ImFabs() calls in NavScoreItem().
3311  //g.OverlayDrawList.AddRect(g.NavScoringRectScreen.Min, g.NavScoringRectScreen.Max, IM_COL32(255,200,0,255)); // [DEBUG]
3312  g.NavScoringCount = 0;
3313 #if IMGUI_DEBUG_NAV_RECTS
3314  if (g.NavWindow) { for (int layer = 0; layer < 2; layer++) GetOverlayDrawList()->AddRect(g.NavWindow->Pos + g.NavWindow->NavRectRel[layer].Min, g.NavWindow->Pos + g.NavWindow->NavRectRel[layer].Max, IM_COL32(255,200,0,255)); } // [DEBUG]
3315  if (g.NavWindow) { ImU32 col = (g.NavWindow->HiddenFrames == 0) ? IM_COL32(255,0,255,255) : IM_COL32(255,0,0,255); ImVec2 p = NavCalcPreferredRefPos(); char buf[32]; ImFormatString(buf, 32, "%d", g.NavLayer); g.OverlayDrawList.AddCircleFilled(p, 3.0f, col); g.OverlayDrawList.AddText(NULL, 13.0f, p + ImVec2(8,-4), col, buf); }
3316 #endif
3317 }
3318 
3319 static void ImGui::UpdateMovingWindow()
3320 {
3321  ImGuiContext& g = *GImGui;
3322  if (g.MovingWindow != NULL)
3323  {
3324  // We actually want to move the root window. g.MovingWindow == window we clicked on (could be a child window).
3325  // We track it to preserve Focus and so that generally ActiveIdWindow == MovingWindow and ActiveId == MovingWindow->MoveId for consistency.
3326  KeepAliveID(g.ActiveId);
3328  ImGuiWindow* moving_window = g.MovingWindow->RootWindow;
3329  if (g.IO.MouseDown[0] && IsMousePosValid(&g.IO.MousePos))
3330  {
3331  ImVec2 pos = g.IO.MousePos - g.ActiveIdClickOffset;
3332  if (moving_window->Pos.x != pos.x || moving_window->Pos.y != pos.y)
3333  {
3334  MarkIniSettingsDirty(moving_window);
3335  SetWindowPos(moving_window, pos, ImGuiCond_Always);
3336  }
3338  }
3339  else
3340  {
3341  ClearActiveID();
3342  g.MovingWindow = NULL;
3343  }
3344  }
3345  else
3346  {
3347  // When clicking/dragging from a window that has the _NoMove flag, we still set the ActiveId in order to prevent hovering others.
3348  if (g.ActiveIdWindow && g.ActiveIdWindow->MoveId == g.ActiveId)
3349  {
3350  KeepAliveID(g.ActiveId);
3351  if (!g.IO.MouseDown[0])
3352  ClearActiveID();
3353  }
3354  }
3355 }
3356 
3357 static void ImGui::UpdateMouseInputs()
3358 {
3359  ImGuiContext& g = *GImGui;
3360 
3361  // If mouse just appeared or disappeared (usually denoted by -FLT_MAX component, but in reality we test for -256000.0f) we cancel out movement in MouseDelta
3363  g.IO.MouseDelta = g.IO.MousePos - g.IO.MousePosPrev;
3364  else
3365  g.IO.MouseDelta = ImVec2(0.0f, 0.0f);
3366  if (g.IO.MouseDelta.x != 0.0f || g.IO.MouseDelta.y != 0.0f)
3367  g.NavDisableMouseHover = false;
3368 
3369  g.IO.MousePosPrev = g.IO.MousePos;
3370  for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++)
3371  {
3372  g.IO.MouseClicked[i] = g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] < 0.0f;
3373  g.IO.MouseReleased[i] = !g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] >= 0.0f;
3375  g.IO.MouseDownDuration[i] = g.IO.MouseDown[i] ? (g.IO.MouseDownDuration[i] < 0.0f ? 0.0f : g.IO.MouseDownDuration[i] + g.IO.DeltaTime) : -1.0f;
3376  g.IO.MouseDoubleClicked[i] = false;
3377  if (g.IO.MouseClicked[i])
3378  {
3379  if (g.Time - g.IO.MouseClickedTime[i] < g.IO.MouseDoubleClickTime)
3380  {
3382  g.IO.MouseDoubleClicked[i] = true;
3383  g.IO.MouseClickedTime[i] = -FLT_MAX; // so the third click isn't turned into a double-click
3384  }
3385  else
3386  {
3387  g.IO.MouseClickedTime[i] = g.Time;
3388  }
3389  g.IO.MouseClickedPos[i] = g.IO.MousePos;
3390  g.IO.MouseDragMaxDistanceAbs[i] = ImVec2(0.0f, 0.0f);
3391  g.IO.MouseDragMaxDistanceSqr[i] = 0.0f;
3392  }
3393  else if (g.IO.MouseDown[i])
3394  {
3395  ImVec2 mouse_delta = g.IO.MousePos - g.IO.MouseClickedPos[i];
3396  g.IO.MouseDragMaxDistanceAbs[i].x = ImMax(g.IO.MouseDragMaxDistanceAbs[i].x, mouse_delta.x < 0.0f ? -mouse_delta.x : mouse_delta.x);
3397  g.IO.MouseDragMaxDistanceAbs[i].y = ImMax(g.IO.MouseDragMaxDistanceAbs[i].y, mouse_delta.y < 0.0f ? -mouse_delta.y : mouse_delta.y);
3398  g.IO.MouseDragMaxDistanceSqr[i] = ImMax(g.IO.MouseDragMaxDistanceSqr[i], ImLengthSqr(mouse_delta));
3399  }
3400  if (g.IO.MouseClicked[i]) // Clicking any mouse button reactivate mouse hovering which may have been deactivated by gamepad/keyboard navigation
3401  g.NavDisableMouseHover = false;
3402  }
3403 }
3404 
3405 // The reason this is exposed in imgui_internal.h is: on touch-based system that don't have hovering, we want to dispatch inputs to the right target (imgui vs imgui+app)
3407 {
3408  ImGuiContext& g = *GImGui;
3409 
3410  // Find the window hovered by mouse:
3411  // - Child windows can extend beyond the limit of their parent so we need to derive HoveredRootWindow from HoveredWindow.
3412  // - When moving a window we can skip the search, which also conveniently bypasses the fact that window->WindowRectClipped is lagging as this point of the frame.
3413  // - We also support the moved window toggling the NoInputs flag after moving has started in order to be able to detect windows below it, which is useful for e.g. docking mechanisms.
3414  g.HoveredWindow = (g.MovingWindow && !(g.MovingWindow->Flags & ImGuiWindowFlags_NoInputs)) ? g.MovingWindow : FindHoveredWindow();
3416 
3417  // Modal windows prevents cursor from hovering behind them.
3418  ImGuiWindow* modal_window = GetFrontMostPopupModal();
3419  if (modal_window)
3420  if (g.HoveredRootWindow && !IsWindowChildOf(g.HoveredRootWindow, modal_window))
3421  g.HoveredRootWindow = g.HoveredWindow = NULL;
3422 
3423  // Disabled mouse?
3425  g.HoveredWindow = g.HoveredRootWindow = NULL;
3426 
3427  // We track click ownership. When clicked outside of a window the click is owned by the application and won't report hovering nor request capture even while dragging over our windows afterward.
3428  int mouse_earliest_button_down = -1;
3429  bool mouse_any_down = false;
3430  for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++)
3431  {
3432  if (g.IO.MouseClicked[i])
3433  g.IO.MouseDownOwned[i] = (g.HoveredWindow != NULL) || (!g.OpenPopupStack.empty());
3434  mouse_any_down |= g.IO.MouseDown[i];
3435  if (g.IO.MouseDown[i])
3436  if (mouse_earliest_button_down == -1 || g.IO.MouseClickedTime[i] < g.IO.MouseClickedTime[mouse_earliest_button_down])
3437  mouse_earliest_button_down = i;
3438  }
3439  const bool mouse_avail_to_imgui = (mouse_earliest_button_down == -1) || g.IO.MouseDownOwned[mouse_earliest_button_down];
3440 
3441  // If mouse was first clicked outside of ImGui bounds we also cancel out hovering.
3442  // FIXME: For patterns of drag and drop across OS windows, we may need to rework/remove this test (first committed 311c0ca9 on 2015/02)
3443  const bool mouse_dragging_extern_payload = g.DragDropActive && (g.DragDropSourceFlags & ImGuiDragDropFlags_SourceExtern) != 0;
3444  if (!mouse_avail_to_imgui && !mouse_dragging_extern_payload)
3445  g.HoveredWindow = g.HoveredRootWindow = NULL;
3446 
3447  // Update io.WantCaptureMouse for the user application (true = dispatch mouse info to imgui, false = dispatch mouse info to imgui + app)
3448  if (g.WantCaptureMouseNextFrame != -1)
3450  else
3451  g.IO.WantCaptureMouse = (mouse_avail_to_imgui && (g.HoveredWindow != NULL || mouse_any_down)) || (!g.OpenPopupStack.empty());
3452 
3453  // Update io.WantCaptureKeyboard for the user application (true = dispatch keyboard info to imgui, false = dispatch keyboard info to imgui + app)
3454  if (g.WantCaptureKeyboardNextFrame != -1)
3456  else
3457  g.IO.WantCaptureKeyboard = (g.ActiveId != 0) || (modal_window != NULL);
3459  g.IO.WantCaptureKeyboard = true;
3460 
3461  // Update io.WantTextInput flag, this is to allow systems without a keyboard (e.g. mobile, hand-held) to show a software keyboard if possible
3462  g.IO.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false;
3463 }
3464 
3466 {
3467  IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() or ImGui::SetCurrentContext()?");
3468  ImGuiContext& g = *GImGui;
3469 
3470  // Check user data
3471  // (We pass an error message in the assert expression to make it visible to programmers who are not using a debugger, as most assert handlers display their argument)
3473  IM_ASSERT(g.IO.DeltaTime >= 0.0f && "Need a positive DeltaTime (zero is tolerated but will cause some timing issues)");
3474  IM_ASSERT(g.IO.DisplaySize.x >= 0.0f && g.IO.DisplaySize.y >= 0.0f && "Invalid DisplaySize value");
3475  IM_ASSERT(g.IO.Fonts->Fonts.Size > 0 && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8() ?");
3476  IM_ASSERT(g.IO.Fonts->Fonts[0]->IsLoaded() && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8() ?");
3477  IM_ASSERT(g.Style.CurveTessellationTol > 0.0f && "Invalid style setting");
3478  IM_ASSERT(g.Style.Alpha >= 0.0f && g.Style.Alpha <= 1.0f && "Invalid style setting. Alpha cannot be negative (allows us to avoid a few clamps in color computations)");
3479  IM_ASSERT((g.FrameCount == 0 || g.FrameCountEnded == g.FrameCount) && "Forgot to call Render() or EndFrame() at the end of the previous frame?");
3480  for (int n = 0; n < ImGuiKey_COUNT; n++)
3481  IM_ASSERT(g.IO.KeyMap[n] >= -1 && g.IO.KeyMap[n] < IM_ARRAYSIZE(g.IO.KeysDown) && "io.KeyMap[] contains an out of bound value (need to be 0..512, or -1 for unmapped key)");
3482 
3483  // Perform simple check for required key mapping (we intentionally do NOT check all keys to not pressure user into setting up everything, but Space is required and was only recently added in 1.60 WIP)
3485  IM_ASSERT(g.IO.KeyMap[ImGuiKey_Space] != -1 && "ImGuiKey_Space is not mapped, required for keyboard navigation.");
3486 
3487  // Load settings on first frame (if not explicitly loaded manually before)
3488  if (!g.SettingsLoaded)
3489  {
3491  if (g.IO.IniFilename)
3493  g.SettingsLoaded = true;
3494  }
3495 
3496  // Save settings (with a delay after the last modification, so we don't spam disk too much)
3497  if (g.SettingsDirtyTimer > 0.0f)
3498  {
3500  if (g.SettingsDirtyTimer <= 0.0f)
3501  {
3502  if (g.IO.IniFilename != NULL)
3504  else
3505  g.IO.WantSaveIniSettings = true; // Let user know they can call SaveIniSettingsToMemory(). user will need to clear io.WantSaveIniSettings themselves.
3506  g.SettingsDirtyTimer = 0.0f;
3507  }
3508  }
3509 
3510  g.Time += g.IO.DeltaTime;
3511  g.FrameCount += 1;
3512  g.TooltipOverrideCount = 0;
3513  g.WindowsActiveCount = 0;
3514 
3515  SetCurrentFont(GetDefaultFont());
3516  IM_ASSERT(g.Font->IsLoaded());
3519 
3520  g.OverlayDrawList.Clear();
3524 
3525  // Mark rendering data as invalid to prevent user who may have a handle on it to use it
3526  g.DrawData.Clear();
3527 
3528  // Clear reference to active widget if the widget isn't alive anymore
3529  if (!g.HoveredIdPreviousFrame)
3530  g.HoveredIdTimer = 0.0f;
3532  g.HoveredId = 0;
3533  g.HoveredIdAllowOverlap = false;
3534  if (!g.ActiveIdIsAlive && g.ActiveIdPreviousFrame == g.ActiveId && g.ActiveId != 0)
3535  ClearActiveID();
3536  if (g.ActiveId)
3537  g.ActiveIdTimer += g.IO.DeltaTime;
3539  g.ActiveIdIsAlive = false;
3540  g.ActiveIdIsJustActivated = false;
3542  g.ScalarAsInputTextId = 0;
3543 
3544  // Elapse drag & drop payload
3546  {
3547  ClearDragDrop();
3549  memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal));
3550  }
3552  g.DragDropAcceptIdCurr = 0;
3553  g.DragDropAcceptIdCurrRectSurface = FLT_MAX;
3554 
3555  // Update keyboard input state
3557  for (int i = 0; i < IM_ARRAYSIZE(g.IO.KeysDown); i++)
3558  g.IO.KeysDownDuration[i] = g.IO.KeysDown[i] ? (g.IO.KeysDownDuration[i] < 0.0f ? 0.0f : g.IO.KeysDownDuration[i] + g.IO.DeltaTime) : -1.0f;
3559 
3560  // Update gamepad/keyboard directional navigation
3561  NavUpdate();
3562 
3563  // Update mouse input state
3564  UpdateMouseInputs();
3565 
3566  // Calculate frame-rate for the user, as a purely luxurious feature
3570  g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)IM_ARRAYSIZE(g.FramerateSecPerFrame))) : FLT_MAX;
3571 
3572  // Handle user moving window with mouse (at the beginning of the frame to avoid input lag or sheering)
3573  UpdateMovingWindow();
3575 
3576  if (GetFrontMostPopupModal() != NULL)
3577  g.ModalWindowDarkeningRatio = ImMin(g.ModalWindowDarkeningRatio + g.IO.DeltaTime * 6.0f, 1.0f);
3578  else
3579  g.ModalWindowDarkeningRatio = 0.0f;
3580 
3583  g.PlatformImePos = ImVec2(1.0f, 1.0f); // OS Input Method Editor showing on top-left of our window by default
3584 
3585  // Mouse wheel scrolling, scale
3586  if (g.HoveredWindow && !g.HoveredWindow->Collapsed && (g.IO.MouseWheel != 0.0f || g.IO.MouseWheelH != 0.0f))
3587  {
3588  // If a child window has the ImGuiWindowFlags_NoScrollWithMouse flag, we give a chance to scroll its parent (unless either ImGuiWindowFlags_NoInputs or ImGuiWindowFlags_NoScrollbar are also set).
3589  ImGuiWindow* window = g.HoveredWindow;
3590  ImGuiWindow* scroll_window = window;
3591  while ((scroll_window->Flags & ImGuiWindowFlags_ChildWindow) && (scroll_window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(scroll_window->Flags & ImGuiWindowFlags_NoScrollbar) && !(scroll_window->Flags & ImGuiWindowFlags_NoInputs) && scroll_window->ParentWindow)
3592  scroll_window = scroll_window->ParentWindow;
3593  const bool scroll_allowed = !(scroll_window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(scroll_window->Flags & ImGuiWindowFlags_NoInputs);
3594 
3595  if (g.IO.MouseWheel != 0.0f)
3596  {
3597  if (g.IO.KeyCtrl && g.IO.FontAllowUserScaling)
3598  {
3599  // Zoom / Scale window
3600  const float new_font_scale = ImClamp(window->FontWindowScale + g.IO.MouseWheel * 0.10f, 0.50f, 2.50f);
3601  const float scale = new_font_scale / window->FontWindowScale;
3602  window->FontWindowScale = new_font_scale;
3603 
3604  const ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size;
3605  window->Pos += offset;
3606  window->Size *= scale;
3607  window->SizeFull *= scale;
3608  }
3609  else if (!g.IO.KeyCtrl && scroll_allowed)
3610  {
3611  // Mouse wheel vertical scrolling
3612  float scroll_amount = 5 * scroll_window->CalcFontSize();
3613  scroll_amount = (float)(int)ImMin(scroll_amount, (scroll_window->ContentsRegionRect.GetHeight() + scroll_window->WindowPadding.y * 2.0f) * 0.67f);
3614  SetWindowScrollY(scroll_window, scroll_window->Scroll.y - g.IO.MouseWheel * scroll_amount);
3615  }
3616  }
3617  if (g.IO.MouseWheelH != 0.0f && scroll_allowed)
3618  {
3619  // Mouse wheel horizontal scrolling (for hardware that supports it)
3620  float scroll_amount = scroll_window->CalcFontSize();
3621  if (!g.IO.KeyCtrl && !(window->Flags & ImGuiWindowFlags_NoScrollWithMouse))
3622  SetWindowScrollX(window, window->Scroll.x - g.IO.MouseWheelH * scroll_amount);
3623  }
3624  }
3625 
3626  // Pressing TAB activate widget focus
3627  if (g.ActiveId == 0 && g.NavWindow != NULL && g.NavWindow->Active && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab, false))
3628  {
3629  if (g.NavId != 0 && g.NavIdTabCounter != INT_MAX)
3630  g.NavWindow->FocusIdxTabRequestNext = g.NavIdTabCounter + 1 + (g.IO.KeyShift ? -1 : 1);
3631  else
3632  g.NavWindow->FocusIdxTabRequestNext = g.IO.KeyShift ? -1 : 0;
3633  }
3634  g.NavIdTabCounter = INT_MAX;
3635 
3636  // Mark all windows as not visible
3637  for (int i = 0; i != g.Windows.Size; i++)
3638  {
3639  ImGuiWindow* window = g.Windows[i];
3640  window->WasActive = window->Active;
3641  window->Active = false;
3642  window->WriteAccessed = false;
3643  }
3644 
3645  // Closing the focused window restore focus to the first active root window in descending z-order
3646  if (g.NavWindow && !g.NavWindow->WasActive)
3647  FocusFrontMostActiveWindow(NULL);
3648 
3649  // No window should be open at the beginning of the frame.
3650  // But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear.
3654 
3655  // Create implicit window - we will only render it if the user has added something to it.
3656  // We don't use "Debug" to avoid colliding with user trying to create a "Debug" window with custom flags.
3658  Begin("Debug##Default");
3659 }
3660 
3661 static void* SettingsHandlerWindow_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name)
3662 {
3664  if (!settings)
3665  settings = AddWindowSettings(name);
3666  return (void*)settings;
3667 }
3668 
3669 static void SettingsHandlerWindow_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line)
3670 {
3671  ImGuiWindowSettings* settings = (ImGuiWindowSettings*)entry;
3672  float x, y;
3673  int i;
3674  if (sscanf(line, "Pos=%f,%f", &x, &y) == 2) settings->Pos = ImVec2(x, y);
3675  else if (sscanf(line, "Size=%f,%f", &x, &y) == 2) settings->Size = ImMax(ImVec2(x, y), GImGui->Style.WindowMinSize);
3676  else if (sscanf(line, "Collapsed=%d", &i) == 1) settings->Collapsed = (i != 0);
3677 }
3678 
3679 static void SettingsHandlerWindow_WriteAll(ImGuiContext* imgui_ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf)
3680 {
3681  // Gather data from windows that were active during this session
3682  ImGuiContext& g = *imgui_ctx;
3683  for (int i = 0; i != g.Windows.Size; i++)
3684  {
3685  ImGuiWindow* window = g.Windows[i];
3687  continue;
3688  ImGuiWindowSettings* settings = ImGui::FindWindowSettings(window->ID);
3689  if (!settings)
3690  settings = AddWindowSettings(window->Name);
3691  settings->Pos = window->Pos;
3692  settings->Size = window->SizeFull;
3693  settings->Collapsed = window->Collapsed;
3694  }
3695 
3696  // Write a buffer
3697  // If a window wasn't opened in this session we preserve its settings
3698  buf->reserve(buf->size() + g.SettingsWindows.Size * 96); // ballpark reserve
3699  for (int i = 0; i != g.SettingsWindows.Size; i++)
3700  {
3701  const ImGuiWindowSettings* settings = &g.SettingsWindows[i];
3702  if (settings->Pos.x == FLT_MAX)
3703  continue;
3704  const char* name = settings->Name;
3705  if (const char* p = strstr(name, "###")) // Skip to the "###" marker if any. We don't skip past to match the behavior of GetID()
3706  name = p;
3707  buf->appendf("[%s][%s]\n", handler->TypeName, name);
3708  buf->appendf("Pos=%d,%d\n", (int)settings->Pos.x, (int)settings->Pos.y);
3709  buf->appendf("Size=%d,%d\n", (int)settings->Size.x, (int)settings->Size.y);
3710  buf->appendf("Collapsed=%d\n", settings->Collapsed);
3711  buf->appendf("\n");
3712  }
3713 }
3714 
3716 {
3717  ImGuiContext& g = *context;
3719 
3720  // Add .ini handle for ImGuiWindow type
3721  ImGuiSettingsHandler ini_handler;
3722  ini_handler.TypeName = "Window";
3723  ini_handler.TypeHash = ImHash("Window", 0, 0);
3724  ini_handler.ReadOpenFn = SettingsHandlerWindow_ReadOpen;
3725  ini_handler.ReadLineFn = SettingsHandlerWindow_ReadLine;
3726  ini_handler.WriteAllFn = SettingsHandlerWindow_WriteAll;
3727  g.SettingsHandlers.push_front(ini_handler);
3728 
3729  g.Initialized = true;
3730 }
3731 
3732 // This function is merely here to free heap allocations.
3734 {
3735  // The fonts atlas can be used prior to calling NewFrame(), so we clear it even if g.Initialized is FALSE (which would happen if we never called NewFrame)
3736  ImGuiContext& g = *context;
3737  if (g.IO.Fonts && g.FontAtlasOwnedByContext)
3738  IM_DELETE(g.IO.Fonts);
3739  g.IO.Fonts = NULL;
3740 
3741  // Cleanup of other data are conditional on actually having initialized ImGui.
3742  if (!g.Initialized)
3743  return;
3744 
3745  // Save settings (unless we haven't attempted to load them: CreateContext/DestroyContext without a call to NewFrame shouldn't save an empty file)
3746  if (g.SettingsLoaded && g.IO.IniFilename != NULL)
3748 
3749  // Clear everything else
3750  for (int i = 0; i < g.Windows.Size; i++)
3751  IM_DELETE(g.Windows[i]);
3752  g.Windows.clear();
3754  g.CurrentWindow = NULL;
3756  g.WindowsById.Clear();
3757  g.NavWindow = NULL;
3758  g.HoveredWindow = NULL;
3759  g.HoveredRootWindow = NULL;
3760  g.ActiveIdWindow = NULL;
3761  g.MovingWindow = NULL;
3762  g.ColorModifiers.clear();
3763  g.StyleModifiers.clear();
3764  g.FontStack.clear();
3765  g.OpenPopupStack.clear();
3769  g.PrivateClipboard.clear();
3773 
3774  for (int i = 0; i < g.SettingsWindows.Size; i++)
3775  IM_DELETE(g.SettingsWindows[i].Name);
3776  g.SettingsWindows.clear();
3777  g.SettingsHandlers.clear();
3778 
3779  if (g.LogFile && g.LogFile != stdout)
3780  {
3781  fclose(g.LogFile);
3782  g.LogFile = NULL;
3783  }
3784  g.LogClipboard.clear();
3785 
3786  g.Initialized = false;
3787 }
3788 
3790 {
3791  ImGuiContext& g = *GImGui;
3792  for (int i = 0; i != g.SettingsWindows.Size; i++)
3793  if (g.SettingsWindows[i].Id == id)
3794  return &g.SettingsWindows[i];
3795  return NULL;
3796 }
3797 
3798 static ImGuiWindowSettings* AddWindowSettings(const char* name)
3799 {
3800  ImGuiContext& g = *GImGui;
3802  ImGuiWindowSettings* settings = &g.SettingsWindows.back();
3803  settings->Name = ImStrdup(name);
3804  settings->Id = ImHash(name, 0);
3805  return settings;
3806 }
3807 
3808 void ImGui::LoadIniSettingsFromDisk(const char* ini_filename)
3809 {
3810  size_t file_data_size = 0;
3811  char* file_data = (char*)ImFileLoadToMemory(ini_filename, "rb", &file_data_size);
3812  if (!file_data)
3813  return;
3814  LoadIniSettingsFromMemory(file_data, (size_t)file_data_size);
3815  ImGui::MemFree(file_data);
3816 }
3817 
3819 {
3820  ImGuiContext& g = *GImGui;
3821  const ImGuiID type_hash = ImHash(type_name, 0, 0);
3822  for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
3823  if (g.SettingsHandlers[handler_n].TypeHash == type_hash)
3824  return &g.SettingsHandlers[handler_n];
3825  return NULL;
3826 }
3827 
3828 // Zero-tolerance, no error reporting, cheap .ini parsing
3829 void ImGui::LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size)
3830 {
3831  ImGuiContext& g = *GImGui;
3833  IM_ASSERT(g.SettingsLoaded == false && g.FrameCount == 0);
3834 
3835  // For user convenience, we allow passing a non zero-terminated string (hence the ini_size parameter).
3836  // For our convenience and to make the code simpler, we'll also write zero-terminators within the buffer. So let's create a writable copy..
3837  if (ini_size == 0)
3838  ini_size = strlen(ini_data);
3839  char* buf = (char*)ImGui::MemAlloc(ini_size + 1);
3840  char* buf_end = buf + ini_size;
3841  memcpy(buf, ini_data, ini_size);
3842  buf[ini_size] = 0;
3843 
3844  void* entry_data = NULL;
3845  ImGuiSettingsHandler* entry_handler = NULL;
3846 
3847  char* line_end = NULL;
3848  for (char* line = buf; line < buf_end; line = line_end + 1)
3849  {
3850  // Skip new lines markers, then find end of the line
3851  while (*line == '\n' || *line == '\r')
3852  line++;
3853  line_end = line;
3854  while (line_end < buf_end && *line_end != '\n' && *line_end != '\r')
3855  line_end++;
3856  line_end[0] = 0;
3857 
3858  if (line[0] == '[' && line_end > line && line_end[-1] == ']')
3859  {
3860  // Parse "[Type][Name]". Note that 'Name' can itself contains [] characters, which is acceptable with the current format and parsing code.
3861  line_end[-1] = 0;
3862  const char* name_end = line_end - 1;
3863  const char* type_start = line + 1;
3864  char* type_end = (char*)(intptr_t)ImStrchrRange(type_start, name_end, ']');
3865  const char* name_start = type_end ? ImStrchrRange(type_end + 1, name_end, '[') : NULL;
3866  if (!type_end || !name_start)
3867  {
3868  name_start = type_start; // Import legacy entries that have no type
3869  type_start = "Window";
3870  }
3871  else
3872  {
3873  *type_end = 0; // Overwrite first ']'
3874  name_start++; // Skip second '['
3875  }
3876  entry_handler = FindSettingsHandler(type_start);
3877  entry_data = entry_handler ? entry_handler->ReadOpenFn(&g, entry_handler, name_start) : NULL;
3878  }
3879  else if (entry_handler != NULL && entry_data != NULL)
3880  {
3881  // Let type handler parse the line
3882  entry_handler->ReadLineFn(&g, entry_handler, entry_data, line);
3883  }
3884  }
3885  ImGui::MemFree(buf);
3886  g.SettingsLoaded = true;
3887 }
3888 
3889 void ImGui::SaveIniSettingsToDisk(const char* ini_filename)
3890 {
3891  ImGuiContext& g = *GImGui;
3892  g.SettingsDirtyTimer = 0.0f;
3893  if (!ini_filename)
3894  return;
3895 
3896  size_t ini_data_size = 0;
3897  const char* ini_data = SaveIniSettingsToMemory(&ini_data_size);
3898  FILE* f = ImFileOpen(ini_filename, "wt");
3899  if (!f)
3900  return;
3901  fwrite(ini_data, sizeof(char), ini_data_size, f);
3902  fclose(f);
3903 }
3904 
3905 // Call registered handlers (e.g. SettingsHandlerWindow_WriteAll() + custom handlers) to write their stuff into a text buffer
3906 const char* ImGui::SaveIniSettingsToMemory(size_t* out_size)
3907 {
3908  ImGuiContext& g = *GImGui;
3909  g.SettingsDirtyTimer = 0.0f;
3910  g.SettingsIniData.Buf.resize(0);
3912  for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
3913  {
3914  ImGuiSettingsHandler* handler = &g.SettingsHandlers[handler_n];
3915  handler->WriteAllFn(&g, handler, &g.SettingsIniData);
3916  }
3917  if (out_size)
3918  *out_size = (size_t)g.SettingsIniData.size();
3919  return g.SettingsIniData.c_str();
3920 }
3921 
3923 {
3924  ImGuiContext& g = *GImGui;
3925  if (g.SettingsDirtyTimer <= 0.0f)
3927 }
3928 
3930 {
3931  ImGuiContext& g = *GImGui;
3932  if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings))
3933  if (g.SettingsDirtyTimer <= 0.0f)
3935 }
3936 
3937 // FIXME: Add a more explicit sort order in the window structure.
3938 static int IMGUI_CDECL ChildWindowComparer(const void* lhs, const void* rhs)
3939 {
3940  const ImGuiWindow* const a = *(const ImGuiWindow* const *)lhs;
3941  const ImGuiWindow* const b = *(const ImGuiWindow* const *)rhs;
3942  if (int d = (a->Flags & ImGuiWindowFlags_Popup) - (b->Flags & ImGuiWindowFlags_Popup))
3943  return d;
3944  if (int d = (a->Flags & ImGuiWindowFlags_Tooltip) - (b->Flags & ImGuiWindowFlags_Tooltip))
3945  return d;
3947 }
3948 
3949 static void AddWindowToSortedBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window)
3950 {
3951  out_sorted_windows->push_back(window);
3952  if (window->Active)
3953  {
3954  int count = window->DC.ChildWindows.Size;
3955  if (count > 1)
3956  qsort(window->DC.ChildWindows.begin(), (size_t)count, sizeof(ImGuiWindow*), ChildWindowComparer);
3957  for (int i = 0; i < count; i++)
3958  {
3959  ImGuiWindow* child = window->DC.ChildWindows[i];
3960  if (child->Active)
3961  AddWindowToSortedBuffer(out_sorted_windows, child);
3962  }
3963  }
3964 }
3965 
3966 static void AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* draw_list)
3967 {
3968  if (draw_list->CmdBuffer.empty())
3969  return;
3970 
3971  // Remove trailing command if unused
3972  ImDrawCmd& last_cmd = draw_list->CmdBuffer.back();
3973  if (last_cmd.ElemCount == 0 && last_cmd.UserCallback == NULL)
3974  {
3975  draw_list->CmdBuffer.pop_back();
3976  if (draw_list->CmdBuffer.empty())
3977  return;
3978  }
3979 
3980  // Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc. May trigger for you if you are using PrimXXX functions incorrectly.
3981  IM_ASSERT(draw_list->VtxBuffer.Size == 0 || draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size);
3982  IM_ASSERT(draw_list->IdxBuffer.Size == 0 || draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size);
3983  IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size);
3984 
3985  // Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = unsigned short = 2 bytes = 64K vertices per ImDrawList = per window)
3986  // If this assert triggers because you are drawing lots of stuff manually:
3987  // A) Make sure you are coarse clipping, because ImDrawList let all your vertices pass. You can use the Metrics window to inspect draw list contents.
3988  // B) If you need/want meshes with more than 64K vertices, uncomment the '#define ImDrawIdx unsigned int' line in imconfig.h to set the index size to 4 bytes.
3989  // You'll need to handle the 4-bytes indices to your renderer. For example, the OpenGL example code detect index size at compile-time by doing:
3990  // glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset);
3991  // Your own engine or render API may use different parameters or function calls to specify index sizes. 2 and 4 bytes indices are generally supported by most API.
3992  // C) If for some reason you cannot use 4 bytes indices or don't want to, a workaround is to call BeginChild()/EndChild() before reaching the 64K limit to split your draw commands in multiple draw lists.
3993  if (sizeof(ImDrawIdx) == 2)
3994  IM_ASSERT(draw_list->_VtxCurrentIdx < (1 << 16) && "Too many vertices in ImDrawList using 16-bit indices. Read comment above");
3995 
3996  out_list->push_back(draw_list);
3997 }
3998 
3999 static void AddWindowToDrawData(ImVector<ImDrawList*>* out_render_list, ImGuiWindow* window)
4000 {
4001  AddDrawListToDrawData(out_render_list, window->DrawList);
4002  for (int i = 0; i < window->DC.ChildWindows.Size; i++)
4003  {
4004  ImGuiWindow* child = window->DC.ChildWindows[i];
4005  if (child->Active && child->HiddenFrames == 0) // clipped children may have been marked not active
4006  AddWindowToDrawData(out_render_list, child);
4007  }
4008 }
4009 
4010 static void AddWindowToDrawDataSelectLayer(ImGuiWindow* window)
4011 {
4012  ImGuiContext& g = *GImGui;
4014  if (window->Flags & ImGuiWindowFlags_Tooltip)
4015  AddWindowToDrawData(&g.DrawDataBuilder.Layers[1], window);
4016  else
4017  AddWindowToDrawData(&g.DrawDataBuilder.Layers[0], window);
4018 }
4019 
4021 {
4022  int n = Layers[0].Size;
4023  int size = n;
4024  for (int i = 1; i < IM_ARRAYSIZE(Layers); i++)
4025  size += Layers[i].Size;
4026  Layers[0].resize(size);
4027  for (int layer_n = 1; layer_n < IM_ARRAYSIZE(Layers); layer_n++)
4028  {
4029  ImVector<ImDrawList*>& layer = Layers[layer_n];
4030  if (layer.empty())
4031  continue;
4032  memcpy(&Layers[0][n], &layer[0], layer.Size * sizeof(ImDrawList*));
4033  n += layer.Size;
4034  layer.resize(0);
4035  }
4036 }
4037 
4038 static void SetupDrawData(ImVector<ImDrawList*>* draw_lists, ImDrawData* out_draw_data)
4039 {
4040  out_draw_data->Valid = true;
4041  out_draw_data->CmdLists = (draw_lists->Size > 0) ? draw_lists->Data : NULL;
4042  out_draw_data->CmdListsCount = draw_lists->Size;
4043  out_draw_data->TotalVtxCount = out_draw_data->TotalIdxCount = 0;
4044  for (int n = 0; n < draw_lists->Size; n++)
4045  {
4046  out_draw_data->TotalVtxCount += draw_lists->Data[n]->VtxBuffer.Size;
4047  out_draw_data->TotalIdxCount += draw_lists->Data[n]->IdxBuffer.Size;
4048  }
4049 }
4050 
4051 // When using this function it is sane to ensure that float are perfectly rounded to integer values, to that e.g. (int)(max.x-min.x) in user's render produce correct result.
4052 void ImGui::PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect)
4053 {
4054  ImGuiWindow* window = GetCurrentWindow();
4055  window->DrawList->PushClipRect(clip_rect_min, clip_rect_max, intersect_with_current_clip_rect);
4056  window->ClipRect = window->DrawList->_ClipRectStack.back();
4057 }
4058 
4060 {
4061  ImGuiWindow* window = GetCurrentWindow();
4062  window->DrawList->PopClipRect();
4063  window->ClipRect = window->DrawList->_ClipRectStack.back();
4064 }
4065 
4066 // This is normally called by Render(). You may want to call it directly if you want to avoid calling Render() but the gain will be very minimal.
4068 {
4069  ImGuiContext& g = *GImGui;
4070  IM_ASSERT(g.Initialized); // Forgot to call ImGui::NewFrame()
4071  if (g.FrameCountEnded == g.FrameCount) // Don't process EndFrame() multiple times.
4072  return;
4073 
4074  // Notify OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME)
4075  if (g.IO.ImeSetInputScreenPosFn && ImLengthSqr(g.PlatformImeLastPos - g.PlatformImePos) > 0.0001f)
4076  {
4079  }
4080 
4081  // Hide implicit "Debug" window if it hasn't been used
4082  IM_ASSERT(g.CurrentWindowStack.Size == 1); // Mismatched Begin()/End() calls
4084  g.CurrentWindow->Active = false;
4085  End();
4086 
4087  if (g.ActiveId == 0 && g.HoveredId == 0)
4088  {
4089  if (!g.NavWindow || !g.NavWindow->Appearing) // Unless we just made a window/popup appear
4090  {
4091  // Click to focus window and start moving (after we're done with all our widgets)
4092  if (g.IO.MouseClicked[0])
4093  {
4094  if (g.HoveredRootWindow != NULL)
4095  {
4096  // Set ActiveId even if the _NoMove flag is set, without it dragging away from a window with _NoMove would activate hover on other windows.
4099  g.NavDisableHighlight = true;
4103  }
4104  else if (g.NavWindow != NULL && GetFrontMostPopupModal() == NULL)
4105  {
4106  // Clicking on void disable focus
4107  FocusWindow(NULL);
4108  }
4109  }
4110 
4111  // With right mouse button we close popups without changing focus
4112  // (The left mouse button path calls FocusWindow which will lead NewFrame->ClosePopupsOverWindow to trigger)
4113  if (g.IO.MouseClicked[1])
4114  {
4115  // Find the top-most window between HoveredWindow and the front most Modal Window.
4116  // This is where we can trim the popup stack.
4118  bool hovered_window_above_modal = false;
4119  if (modal == NULL)
4120  hovered_window_above_modal = true;
4121  for (int i = g.Windows.Size - 1; i >= 0 && hovered_window_above_modal == false; i--)
4122  {
4123  ImGuiWindow* window = g.Windows[i];
4124  if (window == modal)
4125  break;
4126  if (window == g.HoveredWindow)
4127  hovered_window_above_modal = true;
4128  }
4129  ClosePopupsOverWindow(hovered_window_above_modal ? g.HoveredWindow : modal);
4130  }
4131  }
4132  }
4133 
4134  // Sort the window list so that all child windows are after their parent
4135  // We cannot do that on FocusWindow() because childs may not exist yet
4138  for (int i = 0; i != g.Windows.Size; i++)
4139  {
4140  ImGuiWindow* window = g.Windows[i];
4141  if (window->Active && (window->Flags & ImGuiWindowFlags_ChildWindow)) // if a child is active its parent will add it
4142  continue;
4143  AddWindowToSortedBuffer(&g.WindowsSortBuffer, window);
4144  }
4145 
4146  IM_ASSERT(g.Windows.Size == g.WindowsSortBuffer.Size); // we done something wrong
4148 
4149  // Clear Input data for next frame
4150  g.IO.MouseWheel = g.IO.MouseWheelH = 0.0f;
4151  memset(g.IO.InputCharacters, 0, sizeof(g.IO.InputCharacters));
4152  memset(g.IO.NavInputs, 0, sizeof(g.IO.NavInputs));
4153 
4155 }
4156 
4158 {
4159  ImGuiContext& g = *GImGui;
4160  IM_ASSERT(g.Initialized); // Forgot to call ImGui::NewFrame()
4161 
4162  if (g.FrameCountEnded != g.FrameCount)
4163  ImGui::EndFrame();
4165 
4166  // Gather windows to render
4168  g.DrawDataBuilder.Clear();
4170  for (int n = 0; n != g.Windows.Size; n++)
4171  {
4172  ImGuiWindow* window = g.Windows[n];
4173  if (window->Active && window->HiddenFrames == 0 && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0 && window != window_to_render_front_most)
4174  AddWindowToDrawDataSelectLayer(window);
4175  }
4176  if (window_to_render_front_most && window_to_render_front_most->Active && window_to_render_front_most->HiddenFrames == 0) // NavWindowingTarget is always temporarily displayed as the front-most window
4177  AddWindowToDrawDataSelectLayer(window_to_render_front_most);
4179 
4180  // Draw software mouse cursor if requested
4181  ImVec2 offset, size, uv[4];
4182  if (g.IO.MouseDrawCursor && g.IO.Fonts->GetMouseCursorTexData(g.MouseCursor, &offset, &size, &uv[0], &uv[2]))
4183  {
4184  const ImVec2 pos = g.IO.MousePos - offset;
4185  const ImTextureID tex_id = g.IO.Fonts->TexID;
4186  const float sc = g.Style.MouseCursorScale;
4187  g.OverlayDrawList.PushTextureID(tex_id);
4188  g.OverlayDrawList.AddImage(tex_id, pos + ImVec2(1,0)*sc, pos+ImVec2(1,0)*sc + size*sc, uv[2], uv[3], IM_COL32(0,0,0,48)); // Shadow
4189  g.OverlayDrawList.AddImage(tex_id, pos + ImVec2(2,0)*sc, pos+ImVec2(2,0)*sc + size*sc, uv[2], uv[3], IM_COL32(0,0,0,48)); // Shadow
4190  g.OverlayDrawList.AddImage(tex_id, pos, pos + size*sc, uv[2], uv[3], IM_COL32(0,0,0,255)); // Black border
4191  g.OverlayDrawList.AddImage(tex_id, pos, pos + size*sc, uv[0], uv[1], IM_COL32(255,255,255,255)); // White fill
4193  }
4194  if (!g.OverlayDrawList.VtxBuffer.empty())
4195  AddDrawListToDrawData(&g.DrawDataBuilder.Layers[0], &g.OverlayDrawList);
4196 
4197  // Setup ImDrawData structure for end-user
4198  SetupDrawData(&g.DrawDataBuilder.Layers[0], &g.DrawData);
4201 
4202  // Render. If user hasn't set a callback then they may retrieve the draw data via GetDrawData()
4203 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
4204  if (g.DrawData.CmdListsCount > 0 && g.IO.RenderDrawListsFn != NULL)
4206 #endif
4207 }
4208 
4209 const char* ImGui::FindRenderedTextEnd(const char* text, const char* text_end)
4210 {
4211  const char* text_display_end = text;
4212  if (!text_end)
4213  text_end = (const char*)-1;
4214 
4215  while (text_display_end < text_end && *text_display_end != '\0' && (text_display_end[0] != '#' || text_display_end[1] != '#'))
4216  text_display_end++;
4217  return text_display_end;
4218 }
4219 
4220 // Pass text data straight to log (without being displayed)
4221 void ImGui::LogText(const char* fmt, ...)
4222 {
4223  ImGuiContext& g = *GImGui;
4224  if (!g.LogEnabled)
4225  return;
4226 
4227  va_list args;
4228  va_start(args, fmt);
4229  if (g.LogFile)
4230  vfprintf(g.LogFile, fmt, args);
4231  else
4232  g.LogClipboard.appendfv(fmt, args);
4233  va_end(args);
4234 }
4235 
4236 // Internal version that takes a position to decide on newline placement and pad items according to their depth.
4237 // We split text into individual lines to add current tree level padding
4238 static void LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end = NULL)
4239 {
4240  ImGuiContext& g = *GImGui;
4241  ImGuiWindow* window = g.CurrentWindow;
4242 
4243  if (!text_end)
4244  text_end = ImGui::FindRenderedTextEnd(text, text_end);
4245 
4246  const bool log_new_line = ref_pos && (ref_pos->y > window->DC.LogLinePosY + 1);
4247  if (ref_pos)
4248  window->DC.LogLinePosY = ref_pos->y;
4249 
4250  const char* text_remaining = text;
4251  if (g.LogStartDepth > window->DC.TreeDepth) // Re-adjust padding if we have popped out of our starting depth
4252  g.LogStartDepth = window->DC.TreeDepth;
4253  const int tree_depth = (window->DC.TreeDepth - g.LogStartDepth);
4254  for (;;)
4255  {
4256  // Split the string. Each new line (after a '\n') is followed by spacing corresponding to the current depth of our log entry.
4257  const char* line_end = text_remaining;
4258  while (line_end < text_end)
4259  if (*line_end == '\n')
4260  break;
4261  else
4262  line_end++;
4263  if (line_end >= text_end)
4264  line_end = NULL;
4265 
4266  const bool is_first_line = (text == text_remaining);
4267  bool is_last_line = false;
4268  if (line_end == NULL)
4269  {
4270  is_last_line = true;
4271  line_end = text_end;
4272  }
4273  if (line_end != NULL && !(is_last_line && (line_end - text_remaining)==0))
4274  {
4275  const int char_count = (int)(line_end - text_remaining);
4276  if (log_new_line || !is_first_line)
4277  ImGui::LogText(IM_NEWLINE "%*s%.*s", tree_depth*4, "", char_count, text_remaining);
4278  else
4279  ImGui::LogText(" %.*s", char_count, text_remaining);
4280  }
4281 
4282  if (is_last_line)
4283  break;
4284  text_remaining = line_end + 1;
4285  }
4286 }
4287 
4288 // Internal ImGui functions to render text
4289 // RenderText***() functions calls ImDrawList::AddText() calls ImBitmapFont::RenderText()
4290 void ImGui::RenderText(ImVec2 pos, const char* text, const char* text_end, bool hide_text_after_hash)
4291 {
4292  ImGuiContext& g = *GImGui;
4293  ImGuiWindow* window = g.CurrentWindow;
4294 
4295  // Hide anything after a '##' string
4296  const char* text_display_end;
4297  if (hide_text_after_hash)
4298  {
4299  text_display_end = FindRenderedTextEnd(text, text_end);
4300  }
4301  else
4302  {
4303  if (!text_end)
4304  text_end = text + strlen(text); // FIXME-OPT
4305  text_display_end = text_end;
4306  }
4307 
4308  if (text != text_display_end)
4309  {
4310  window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end);
4311  if (g.LogEnabled)
4312  LogRenderedText(&pos, text, text_display_end);
4313  }
4314 }
4315 
4316 void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width)
4317 {
4318  ImGuiContext& g = *GImGui;
4319  ImGuiWindow* window = g.CurrentWindow;
4320 
4321  if (!text_end)
4322  text_end = text + strlen(text); // FIXME-OPT
4323 
4324  if (text != text_end)
4325  {
4326  window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_end, wrap_width);
4327  if (g.LogEnabled)
4328  LogRenderedText(&pos, text, text_end);
4329  }
4330 }
4331 
4332 // Default clip_rect uses (pos_min,pos_max)
4333 // Handle clipping on CPU immediately (vs typically let the GPU clip the triangles that are overlapping the clipping rectangle edges)
4334 void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect)
4335 {
4336  // Hide anything after a '##' string
4337  const char* text_display_end = FindRenderedTextEnd(text, text_end);
4338  const int text_len = (int)(text_display_end - text);
4339  if (text_len == 0)
4340  return;
4341 
4342  ImGuiContext& g = *GImGui;
4343  ImGuiWindow* window = g.CurrentWindow;
4344 
4345  // Perform CPU side clipping for single clipped element to avoid using scissor state
4346  ImVec2 pos = pos_min;
4347  const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_display_end, false, 0.0f);
4348 
4349  const ImVec2* clip_min = clip_rect ? &clip_rect->Min : &pos_min;
4350  const ImVec2* clip_max = clip_rect ? &clip_rect->Max : &pos_max;
4351  bool need_clipping = (pos.x + text_size.x >= clip_max->x) || (pos.y + text_size.y >= clip_max->y);
4352  if (clip_rect) // If we had no explicit clipping rectangle then pos==clip_min
4353  need_clipping |= (pos.x < clip_min->x) || (pos.y < clip_min->y);
4354 
4355  // Align whole block. We should defer that to the better rendering function when we'll have support for individual line alignment.
4356  if (align.x > 0.0f) pos.x = ImMax(pos.x, pos.x + (pos_max.x - pos.x - text_size.x) * align.x);
4357  if (align.y > 0.0f) pos.y = ImMax(pos.y, pos.y + (pos_max.y - pos.y - text_size.y) * align.y);
4358 
4359  // Render
4360  if (need_clipping)
4361  {
4362  ImVec4 fine_clip_rect(clip_min->x, clip_min->y, clip_max->x, clip_max->y);
4363  window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, &fine_clip_rect);
4364  }
4365  else
4366  {
4367  window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, NULL);
4368  }
4369  if (g.LogEnabled)
4370  LogRenderedText(&pos, text, text_display_end);
4371 }
4372 
4373 // Render a rectangle shaped with optional rounding and borders
4374 void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, float rounding)
4375 {
4376  ImGuiContext& g = *GImGui;
4377  ImGuiWindow* window = g.CurrentWindow;
4378  window->DrawList->AddRectFilled(p_min, p_max, fill_col, rounding);
4379  const float border_size = g.Style.FrameBorderSize;
4380  if (border && border_size > 0.0f)
4381  {
4382  window->DrawList->AddRect(p_min+ImVec2(1,1), p_max+ImVec2(1,1), GetColorU32(ImGuiCol_BorderShadow), rounding, ImDrawCornerFlags_All, border_size);
4383  window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size);
4384  }
4385 }
4386 
4387 void ImGui::RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding)
4388 {
4389  ImGuiContext& g = *GImGui;
4390  ImGuiWindow* window = g.CurrentWindow;
4391  const float border_size = g.Style.FrameBorderSize;
4392  if (border_size > 0.0f)
4393  {
4394  window->DrawList->AddRect(p_min+ImVec2(1,1), p_max+ImVec2(1,1), GetColorU32(ImGuiCol_BorderShadow), rounding, ImDrawCornerFlags_All, border_size);
4395  window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size);
4396  }
4397 }
4398 
4399 // Render a triangle to denote expanded/collapsed state
4400 void ImGui::RenderArrow(ImVec2 p_min, ImGuiDir dir, float scale)
4401 {
4402  ImGuiContext& g = *GImGui;
4403  ImGuiWindow* window = g.CurrentWindow;
4404 
4405  const float h = g.FontSize * 1.00f;
4406  float r = h * 0.40f * scale;
4407  ImVec2 center = p_min + ImVec2(h * 0.50f, h * 0.50f * scale);
4408 
4409  ImVec2 a, b, c;
4410  switch (dir)
4411  {
4412  case ImGuiDir_Up:
4413  case ImGuiDir_Down:
4414  if (dir == ImGuiDir_Up) r = -r;
4415  center.y -= r * 0.25f;
4416  a = ImVec2(0,1) * r;
4417  b = ImVec2(-0.866f,-0.5f) * r;
4418  c = ImVec2(+0.866f,-0.5f) * r;
4419  break;
4420  case ImGuiDir_Left:
4421  case ImGuiDir_Right:
4422  if (dir == ImGuiDir_Left) r = -r;
4423  center.x -= r * 0.25f;
4424  a = ImVec2(1,0) * r;
4425  b = ImVec2(-0.500f,+0.866f) * r;
4426  c = ImVec2(-0.500f,-0.866f) * r;
4427  break;
4428  case ImGuiDir_None:
4429  case ImGuiDir_COUNT:
4430  IM_ASSERT(0);
4431  break;
4432  }
4433 
4434  window->DrawList->AddTriangleFilled(center + a, center + b, center + c, GetColorU32(ImGuiCol_Text));
4435 }
4436 
4438 {
4439  ImGuiContext& g = *GImGui;
4440  ImGuiWindow* window = g.CurrentWindow;
4441  window->DrawList->AddCircleFilled(pos, GImGui->FontSize*0.20f, GetColorU32(ImGuiCol_Text), 8);
4442 }
4443 
4444 void ImGui::RenderCheckMark(ImVec2 pos, ImU32 col, float sz)
4445 {
4446  ImGuiContext& g = *GImGui;
4447  ImGuiWindow* window = g.CurrentWindow;
4448 
4449  float thickness = ImMax(sz / 5.0f, 1.0f);
4450  sz -= thickness*0.5f;
4451  pos += ImVec2(thickness*0.25f, thickness*0.25f);
4452 
4453  float third = sz / 3.0f;
4454  float bx = pos.x + third;
4455  float by = pos.y + sz - third*0.5f;
4456  window->DrawList->PathLineTo(ImVec2(bx - third, by - third));
4457  window->DrawList->PathLineTo(ImVec2(bx, by));
4458  window->DrawList->PathLineTo(ImVec2(bx + third*2, by - third*2));
4459  window->DrawList->PathStroke(col, false, thickness);
4460 }
4461 
4463 {
4464  ImGuiContext& g = *GImGui;
4465  if (id != g.NavId)
4466  return;
4468  return;
4470  if (window->DC.NavHideHighlightOneFrame)
4471  return;
4472 
4473  float rounding = (flags & ImGuiNavHighlightFlags_NoRounding) ? 0.0f : g.Style.FrameRounding;
4474  ImRect display_rect = bb;
4475  display_rect.ClipWith(window->ClipRect);
4477  {
4478  const float THICKNESS = 2.0f;
4479  const float DISTANCE = 3.0f + THICKNESS * 0.5f;
4480  display_rect.Expand(ImVec2(DISTANCE,DISTANCE));
4481  bool fully_visible = window->ClipRect.Contains(display_rect);
4482  if (!fully_visible)
4483  window->DrawList->PushClipRect(display_rect.Min, display_rect.Max);
4484  window->DrawList->AddRect(display_rect.Min + ImVec2(THICKNESS*0.5f,THICKNESS*0.5f), display_rect.Max - ImVec2(THICKNESS*0.5f,THICKNESS*0.5f), GetColorU32(ImGuiCol_NavHighlight), rounding, ImDrawCornerFlags_All, THICKNESS);
4485  if (!fully_visible)
4486  window->DrawList->PopClipRect();
4487  }
4488  if (flags & ImGuiNavHighlightFlags_TypeThin)
4489  {
4490  window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavHighlight), rounding, ~0, 1.0f);
4491  }
4492 }
4493 
4494 // Calculate text size. Text can be multi-line. Optionally ignore text after a ## marker.
4495 // CalcTextSize("") should return ImVec2(0.0f, GImGui->FontSize)
4496 ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_text_after_double_hash, float wrap_width)
4497 {
4498  ImGuiContext& g = *GImGui;
4499 
4500  const char* text_display_end;
4501  if (hide_text_after_double_hash)
4502  text_display_end = FindRenderedTextEnd(text, text_end); // Hide anything after a '##' string
4503  else
4504  text_display_end = text_end;
4505 
4506  ImFont* font = g.Font;
4507  const float font_size = g.FontSize;
4508  if (text == text_display_end)
4509  return ImVec2(0.0f, font_size);
4510  ImVec2 text_size = font->CalcTextSizeA(font_size, FLT_MAX, wrap_width, text, text_display_end, NULL);
4511 
4512  // Cancel out character spacing for the last character of a line (it is baked into glyph->AdvanceX field)
4513  const float font_scale = font_size / font->FontSize;
4514  const float character_spacing_x = 1.0f * font_scale;
4515  if (text_size.x > 0.0f)
4516  text_size.x -= character_spacing_x;
4517  text_size.x = (float)(int)(text_size.x + 0.95f);
4518 
4519  return text_size;
4520 }
4521 
4522 // Helper to calculate coarse clipping of large list of evenly sized items.
4523 // NB: Prefer using the ImGuiListClipper higher-level helper if you can! Read comments and instructions there on how those use this sort of pattern.
4524 // NB: 'items_count' is only used to clamp the result, if you don't know your count you can use INT_MAX
4525 void ImGui::CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end)
4526 {
4527  ImGuiContext& g = *GImGui;
4528  ImGuiWindow* window = g.CurrentWindow;
4529  if (g.LogEnabled)
4530  {
4531  // If logging is active, do not perform any clipping
4532  *out_items_display_start = 0;
4533  *out_items_display_end = items_count;
4534  return;
4535  }
4536  if (window->SkipItems)
4537  {
4538  *out_items_display_start = *out_items_display_end = 0;
4539  return;
4540  }
4541 
4542  const ImVec2 pos = window->DC.CursorPos;
4543  int start = (int)((window->ClipRect.Min.y - pos.y) / items_height);
4544  int end = (int)((window->ClipRect.Max.y - pos.y) / items_height);
4545  if (g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Up) // When performing a navigation request, ensure we have one item extra in the direction we are moving to
4546  start--;
4547  if (g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Down)
4548  end++;
4549 
4550  start = ImClamp(start, 0, items_count);
4551  end = ImClamp(end + 1, start, items_count);
4552  *out_items_display_start = start;
4553  *out_items_display_end = end;
4554 }
4555 
4556 // Find window given position, search front-to-back
4557 // FIXME: Note that we have a lag here because WindowRectClipped is updated in Begin() so windows moved by user via SetWindowPos() and not SetNextWindowPos() will have that rectangle lagging by a frame at the time FindHoveredWindow() is called, aka before the next Begin(). Moving window thankfully isn't affected.
4558 static ImGuiWindow* FindHoveredWindow()
4559 {
4560  ImGuiContext& g = *GImGui;
4561  for (int i = g.Windows.Size - 1; i >= 0; i--)
4562  {
4563  ImGuiWindow* window = g.Windows[i];
4564  if (!window->Active)
4565  continue;
4566  if (window->Flags & ImGuiWindowFlags_NoInputs)
4567  continue;
4568 
4569  // Using the clipped AABB, a child window will typically be clipped by its parent (not always)
4571  if (bb.Contains(g.IO.MousePos))
4572  return window;
4573  }
4574  return NULL;
4575 }
4576 
4577 // Test if mouse cursor is hovering given rectangle
4578 // NB- Rectangle is clipped by our current clip setting
4579 // NB- Expand the rectangle to be generous on imprecise inputs systems (g.Style.TouchExtraPadding)
4580 bool ImGui::IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip)
4581 {
4582  ImGuiContext& g = *GImGui;
4583 
4584  // Clip
4585  ImRect rect_clipped(r_min, r_max);
4586  if (clip)
4587  rect_clipped.ClipWith(g.CurrentWindow->ClipRect);
4588 
4589  // Expand for touch input
4590  const ImRect rect_for_touch(rect_clipped.Min - g.Style.TouchExtraPadding, rect_clipped.Max + g.Style.TouchExtraPadding);
4591  return rect_for_touch.Contains(g.IO.MousePos);
4592 }
4593 
4594 static bool IsKeyPressedMap(ImGuiKey key, bool repeat)
4595 {
4596  const int key_index = GImGui->IO.KeyMap[key];
4597  return (key_index >= 0) ? ImGui::IsKeyPressed(key_index, repeat) : false;
4598 }
4599 
4601 {
4602  IM_ASSERT(imgui_key >= 0 && imgui_key < ImGuiKey_COUNT);
4603  return GImGui->IO.KeyMap[imgui_key];
4604 }
4605 
4606 // Note that imgui doesn't know the semantic of each entry of io.KeysDown[]. Use your own indices/enums according to how your back-end/engine stored them into io.KeysDown[]!
4607 bool ImGui::IsKeyDown(int user_key_index)
4608 {
4609  if (user_key_index < 0) return false;
4610  IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(GImGui->IO.KeysDown));
4611  return GImGui->IO.KeysDown[user_key_index];
4612 }
4613 
4614 int ImGui::CalcTypematicPressedRepeatAmount(float t, float t_prev, float repeat_delay, float repeat_rate)
4615 {
4616  if (t == 0.0f)
4617  return 1;
4618  if (t <= repeat_delay || repeat_rate <= 0.0f)
4619  return 0;
4620  const int count = (int)((t - repeat_delay) / repeat_rate) - (int)((t_prev - repeat_delay) / repeat_rate);
4621  return (count > 0) ? count : 0;
4622 }
4623 
4624 int ImGui::GetKeyPressedAmount(int key_index, float repeat_delay, float repeat_rate)
4625 {
4626  ImGuiContext& g = *GImGui;
4627  if (key_index < 0) return false;
4628  IM_ASSERT(key_index >= 0 && key_index < IM_ARRAYSIZE(g.IO.KeysDown));
4629  const float t = g.IO.KeysDownDuration[key_index];
4630  return CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, repeat_delay, repeat_rate);
4631 }
4632 
4633 bool ImGui::IsKeyPressed(int user_key_index, bool repeat)
4634 {
4635  ImGuiContext& g = *GImGui;
4636  if (user_key_index < 0) return false;
4637  IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown));
4638  const float t = g.IO.KeysDownDuration[user_key_index];
4639  if (t == 0.0f)
4640  return true;
4641  if (repeat && t > g.IO.KeyRepeatDelay)
4642  return GetKeyPressedAmount(user_key_index, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0;
4643  return false;
4644 }
4645 
4646 bool ImGui::IsKeyReleased(int user_key_index)
4647 {
4648  ImGuiContext& g = *GImGui;
4649  if (user_key_index < 0) return false;
4650  IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown));
4651  return g.IO.KeysDownDurationPrev[user_key_index] >= 0.0f && !g.IO.KeysDown[user_key_index];
4652 }
4653 
4654 bool ImGui::IsMouseDown(int button)
4655 {
4656  ImGuiContext& g = *GImGui;
4657  IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
4658  return g.IO.MouseDown[button];
4659 }
4660 
4662 {
4663  ImGuiContext& g = *GImGui;
4664  for (int n = 0; n < IM_ARRAYSIZE(g.IO.MouseDown); n++)
4665  if (g.IO.MouseDown[n])
4666  return true;
4667  return false;
4668 }
4669 
4670 bool ImGui::IsMouseClicked(int button, bool repeat)
4671 {
4672  ImGuiContext& g = *GImGui;
4673  IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
4674  const float t = g.IO.MouseDownDuration[button];
4675  if (t == 0.0f)
4676  return true;
4677 
4678  if (repeat && t > g.IO.KeyRepeatDelay)
4679  {
4680  float delay = g.IO.KeyRepeatDelay, rate = g.IO.KeyRepeatRate;
4681  if ((ImFmod(t - delay, rate) > rate*0.5f) != (ImFmod(t - delay - g.IO.DeltaTime, rate) > rate*0.5f))
4682  return true;
4683  }
4684 
4685  return false;
4686 }
4687 
4688 bool ImGui::IsMouseReleased(int button)
4689 {
4690  ImGuiContext& g = *GImGui;
4691  IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
4692  return g.IO.MouseReleased[button];
4693 }
4694 
4696 {
4697  ImGuiContext& g = *GImGui;
4698  IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
4699  return g.IO.MouseDoubleClicked[button];
4700 }
4701 
4702 bool ImGui::IsMouseDragging(int button, float lock_threshold)
4703 {
4704  ImGuiContext& g = *GImGui;
4705  IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
4706  if (!g.IO.MouseDown[button])
4707  return false;
4708  if (lock_threshold < 0.0f)
4709  lock_threshold = g.IO.MouseDragThreshold;
4710  return g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold;
4711 }
4712 
4714 {
4715  return GImGui->IO.MousePos;
4716 }
4717 
4718 // NB: prefer to call right after BeginPopup(). At the time Selectable/MenuItem is activated, the popup is already closed!
4720 {
4721  ImGuiContext& g = *GImGui;
4722  if (g.CurrentPopupStack.Size > 0)
4723  return g.OpenPopupStack[g.CurrentPopupStack.Size-1].OpenMousePos;
4724  return g.IO.MousePos;
4725 }
4726 
4727 // We typically use ImVec2(-FLT_MAX,-FLT_MAX) to denote an invalid mouse position
4728 bool ImGui::IsMousePosValid(const ImVec2* mouse_pos)
4729 {
4730  if (mouse_pos == NULL)
4731  mouse_pos = &GImGui->IO.MousePos;
4732  const float MOUSE_INVALID = -256000.0f;
4733  return mouse_pos->x >= MOUSE_INVALID && mouse_pos->y >= MOUSE_INVALID;
4734 }
4735 
4736 // NB: This is only valid if IsMousePosValid(). Back-ends in theory should always keep mouse position valid when dragging even outside the client window.
4737 ImVec2 ImGui::GetMouseDragDelta(int button, float lock_threshold)
4738 {
4739  ImGuiContext& g = *GImGui;
4740  IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
4741  if (lock_threshold < 0.0f)
4742  lock_threshold = g.IO.MouseDragThreshold;
4743  if (g.IO.MouseDown[button])
4744  if (g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold)
4745  return g.IO.MousePos - g.IO.MouseClickedPos[button]; // Assume we can only get active with left-mouse button (at the moment).
4746  return ImVec2(0.0f, 0.0f);
4747 }
4748 
4750 {
4751  ImGuiContext& g = *GImGui;
4752  IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
4753  // NB: We don't need to reset g.IO.MouseDragMaxDistanceSqr
4754  g.IO.MouseClickedPos[button] = g.IO.MousePos;
4755 }
4756 
4758 {
4759  return GImGui->MouseCursor;
4760 }
4761 
4763 {
4764  GImGui->MouseCursor = cursor_type;
4765 }
4766 
4768 {
4769  GImGui->WantCaptureKeyboardNextFrame = capture ? 1 : 0;
4770 }
4771 
4772 void ImGui::CaptureMouseFromApp(bool capture)
4773 {
4774  GImGui->WantCaptureMouseNextFrame = capture ? 1 : 0;
4775 }
4776 
4778 {
4779  ImGuiContext& g = *GImGui;
4780  if (g.ActiveId)
4781  {
4782  ImGuiWindow* window = g.CurrentWindow;
4783  return g.ActiveId == window->DC.LastItemId;
4784  }
4785  return false;
4786 }
4787 
4789 {
4790  ImGuiContext& g = *GImGui;
4791  return g.NavId && !g.NavDisableHighlight && g.NavId == g.CurrentWindow->DC.LastItemId;
4792 }
4793 
4794 bool ImGui::IsItemClicked(int mouse_button)
4795 {
4796  return IsMouseClicked(mouse_button) && IsItemHovered(ImGuiHoveredFlags_Default);
4797 }
4798 
4800 {
4801  ImGuiContext& g = *GImGui;
4802  return g.HoveredId != 0 || g.HoveredIdPreviousFrame != 0;
4803 }
4804 
4806 {
4807  ImGuiContext& g = *GImGui;
4808  return g.ActiveId != 0;
4809 }
4810 
4812 {
4813  ImGuiContext& g = *GImGui;
4814  return g.NavId != 0 && !g.NavDisableHighlight;
4815 }
4816 
4818 {
4819  ImGuiWindow* window = GetCurrentWindowRead();
4820  return window->ClipRect.Overlaps(window->DC.LastItemRect);
4821 }
4822 
4823 // Allow last item to be overlapped by a subsequent item. Both may be activated during the same frame before the later one takes priority.
4825 {
4826  ImGuiContext& g = *GImGui;
4827  if (g.HoveredId == g.CurrentWindow->DC.LastItemId)
4828  g.HoveredIdAllowOverlap = true;
4829  if (g.ActiveId == g.CurrentWindow->DC.LastItemId)
4830  g.ActiveIdAllowOverlap = true;
4831 }
4832 
4834 {
4835  ImGuiWindow* window = GetCurrentWindowRead();
4836  return window->DC.LastItemRect.Min;
4837 }
4838 
4840 {
4841  ImGuiWindow* window = GetCurrentWindowRead();
4842  return window->DC.LastItemRect.Max;
4843 }
4844 
4846 {
4847  ImGuiWindow* window = GetCurrentWindowRead();
4848  return window->DC.LastItemRect.GetSize();
4849 }
4850 
4851 static ImRect GetViewportRect()
4852 {
4853  ImGuiContext& g = *GImGui;
4856  return ImRect(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y);
4857 }
4858 
4859 // Not exposed publicly as BeginTooltip() because bool parameters are evil. Let's see if other needs arise first.
4860 void ImGui::BeginTooltipEx(ImGuiWindowFlags extra_flags, bool override_previous_tooltip)
4861 {
4862  ImGuiContext& g = *GImGui;
4863  char window_name[16];
4864  ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", g.TooltipOverrideCount);
4865  if (override_previous_tooltip)
4866  if (ImGuiWindow* window = FindWindowByName(window_name))
4867  if (window->Active)
4868  {
4869  // Hide previous tooltip from being displayed. We can't easily "reset" the content of a window so we create a new one.
4870  window->HiddenFrames = 1;
4871  ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", ++g.TooltipOverrideCount);
4872  }
4874  Begin(window_name, NULL, flags | extra_flags);
4875 }
4876 
4877 void ImGui::SetTooltipV(const char* fmt, va_list args)
4878 {
4879  BeginTooltipEx(0, true);
4880  TextV(fmt, args);
4881  EndTooltip();
4882 }
4883 
4884 void ImGui::SetTooltip(const char* fmt, ...)
4885 {
4886  va_list args;
4887  va_start(args, fmt);
4888  SetTooltipV(fmt, args);
4889  va_end(args);
4890 }
4891 
4893 {
4894  BeginTooltipEx(0, false);
4895 }
4896 
4898 {
4899  IM_ASSERT(GetCurrentWindowRead()->Flags & ImGuiWindowFlags_Tooltip); // Mismatched BeginTooltip()/EndTooltip() calls
4900  End();
4901 }
4902 
4903 // Mark popup as open (toggle toward open state).
4904 // Popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block.
4905 // Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level).
4906 // One open popup per level of the popup hierarchy (NB: when assigning we reset the Window member of ImGuiPopupRef to NULL)
4908 {
4909  ImGuiContext& g = *GImGui;
4910  ImGuiWindow* parent_window = g.CurrentWindow;
4911  int current_stack_size = g.CurrentPopupStack.Size;
4912  ImGuiPopupRef popup_ref; // Tagged as new ref as Window will be set back to NULL if we write this into OpenPopupStack.
4913  popup_ref.PopupId = id;
4914  popup_ref.Window = NULL;
4915  popup_ref.ParentWindow = parent_window;
4916  popup_ref.OpenFrameCount = g.FrameCount;
4917  popup_ref.OpenParentId = parent_window->IDStack.back();
4918  popup_ref.OpenMousePos = g.IO.MousePos;
4919  popup_ref.OpenPopupPos = NavCalcPreferredRefPos();
4920 
4921  //printf("[%05d] OpenPopupEx(0x%08X)\n", g.FrameCount, id);
4922  if (g.OpenPopupStack.Size < current_stack_size + 1)
4923  {
4924  g.OpenPopupStack.push_back(popup_ref);
4925  }
4926  else
4927  {
4928  // Close child popups if any
4929  g.OpenPopupStack.resize(current_stack_size + 1);
4930 
4931  // Gently handle the user mistakenly calling OpenPopup() every frame. It is a programming mistake! However, if we were to run the regular code path, the ui
4932  // would become completely unusable because the popup will always be in hidden-while-calculating-size state _while_ claiming focus. Which would be a very confusing
4933  // situation for the programmer. Instead, we silently allow the popup to proceed, it will keep reappearing and the programming error will be more obvious to understand.
4934  if (g.OpenPopupStack[current_stack_size].PopupId == id && g.OpenPopupStack[current_stack_size].OpenFrameCount == g.FrameCount - 1)
4935  g.OpenPopupStack[current_stack_size].OpenFrameCount = popup_ref.OpenFrameCount;
4936  else
4937  g.OpenPopupStack[current_stack_size] = popup_ref;
4938 
4939  // When reopening a popup we first refocus its parent, otherwise if its parent is itself a popup it would get closed by ClosePopupsOverWindow().
4940  // This is equivalent to what ClosePopupToLevel() does.
4941  //if (g.OpenPopupStack[current_stack_size].PopupId == id)
4942  // FocusWindow(parent_window);
4943  }
4944 }
4945 
4946 void ImGui::OpenPopup(const char* str_id)
4947 {
4948  ImGuiContext& g = *GImGui;
4949  OpenPopupEx(g.CurrentWindow->GetID(str_id));
4950 }
4951 
4953 {
4954  ImGuiContext& g = *GImGui;
4955  if (g.OpenPopupStack.empty())
4956  return;
4957 
4958  // When popups are stacked, clicking on a lower level popups puts focus back to it and close popups above it.
4959  // Don't close our own child popup windows.
4960  int n = 0;
4961  if (ref_window)
4962  {
4963  for (n = 0; n < g.OpenPopupStack.Size; n++)
4964  {
4965  ImGuiPopupRef& popup = g.OpenPopupStack[n];
4966  if (!popup.Window)
4967  continue;
4968  IM_ASSERT((popup.Window->Flags & ImGuiWindowFlags_Popup) != 0);
4970  continue;
4971 
4972  // Trim the stack if popups are not direct descendant of the reference window (which is often the NavWindow)
4973  bool has_focus = false;
4974  for (int m = n; m < g.OpenPopupStack.Size && !has_focus; m++)
4975  has_focus = (g.OpenPopupStack[m].Window && g.OpenPopupStack[m].Window->RootWindow == ref_window->RootWindow);
4976  if (!has_focus)
4977  break;
4978  }
4979  }
4980  if (n < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the block below
4981  ClosePopupToLevel(n);
4982 }
4983 
4985 {
4986  ImGuiContext& g = *GImGui;
4987  for (int n = g.OpenPopupStack.Size-1; n >= 0; n--)
4988  if (ImGuiWindow* popup = g.OpenPopupStack.Data[n].Window)
4989  if (popup->Flags & ImGuiWindowFlags_Modal)
4990  return popup;
4991  return NULL;
4992 }
4993 
4994 static void ClosePopupToLevel(int remaining)
4995 {
4996  IM_ASSERT(remaining >= 0);
4997  ImGuiContext& g = *GImGui;
4998  ImGuiWindow* focus_window = (remaining > 0) ? g.OpenPopupStack[remaining-1].Window : g.OpenPopupStack[0].ParentWindow;
4999  if (g.NavLayer == 0)
5000  focus_window = NavRestoreLastChildNavWindow(focus_window);
5001  ImGui::FocusWindow(focus_window);
5002  focus_window->DC.NavHideHighlightOneFrame = true;
5003  g.OpenPopupStack.resize(remaining);
5004 }
5005 
5007 {
5008  if (!IsPopupOpen(id))
5009  return;
5010  ImGuiContext& g = *GImGui;
5011  ClosePopupToLevel(g.OpenPopupStack.Size - 1);
5012 }
5013 
5014 // Close the popup we have begin-ed into.
5016 {
5017  ImGuiContext& g = *GImGui;
5018  int popup_idx = g.CurrentPopupStack.Size - 1;
5019  if (popup_idx < 0 || popup_idx >= g.OpenPopupStack.Size || g.CurrentPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId)
5020  return;
5021  while (popup_idx > 0 && g.OpenPopupStack[popup_idx].Window && (g.OpenPopupStack[popup_idx].Window->Flags & ImGuiWindowFlags_ChildMenu))
5022  popup_idx--;
5023  ClosePopupToLevel(popup_idx);
5024 }
5025 
5027 {
5028  ImGuiContext& g = *GImGui;
5029  if (!IsPopupOpen(id))
5030  {
5031  g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values
5032  return false;
5033  }
5034 
5035  char name[20];
5036  if (extra_flags & ImGuiWindowFlags_ChildMenu)
5037  ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.CurrentPopupStack.Size); // Recycle windows based on depth
5038  else
5039  ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id); // Not recycling, so we can close/open during the same frame
5040 
5041  bool is_open = Begin(name, NULL, extra_flags | ImGuiWindowFlags_Popup);
5042  if (!is_open) // NB: Begin can return false when the popup is completely clipped (e.g. zero size display)
5043  EndPopup();
5044 
5045  return is_open;
5046 }
5047 
5048 bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags)
5049 {
5050  ImGuiContext& g = *GImGui;
5051  if (g.OpenPopupStack.Size <= g.CurrentPopupStack.Size) // Early out for performance
5052  {
5053  g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values
5054  return false;
5055  }
5057 }
5058 
5060 {
5061  ImGuiContext& g = *GImGui;
5063 }
5064 
5065 bool ImGui::IsPopupOpen(const char* str_id)
5066 {
5067  ImGuiContext& g = *GImGui;
5069 }
5070 
5071 bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags)
5072 {
5073  ImGuiContext& g = *GImGui;
5074  ImGuiWindow* window = g.CurrentWindow;
5075  const ImGuiID id = window->GetID(name);
5076  if (!IsPopupOpen(id))
5077  {
5078  g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values
5079  return false;
5080  }
5081 
5082  // Center modal windows by default
5083  // FIXME: Should test for (PosCond & window->SetWindowPosAllowFlags) with the upcoming window.
5084  if (g.NextWindowData.PosCond == 0)
5086 
5088  if (!is_open || (p_open && !*p_open)) // NB: is_open can be 'false' when the popup is completely clipped (e.g. zero size display)
5089  {
5090  EndPopup();
5091  if (is_open)
5092  ClosePopup(id);
5093  return false;
5094  }
5095 
5096  return is_open;
5097 }
5098 
5099 static void NavProcessMoveRequestWrapAround(ImGuiWindow* window)
5100 {
5101  ImGuiContext& g = *GImGui;
5102  if (g.NavWindow == window && NavMoveRequestButNoResultYet())
5104  {
5107  g.NavWindow->NavRectRel[0].Min.y = g.NavWindow->NavRectRel[0].Max.y = ((g.NavMoveDir == ImGuiDir_Up) ? ImMax(window->SizeFull.y, window->SizeContents.y) : 0.0f) - window->Scroll.y;
5108  }
5109 }
5110 
5112 {
5113  ImGuiContext& g = *GImGui; (void)g;
5114  IM_ASSERT(g.CurrentWindow->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginPopup()/EndPopup() calls
5116 
5117  // Make all menus and popups wrap around for now, may need to expose that policy.
5118  NavProcessMoveRequestWrapAround(g.CurrentWindow);
5119 
5120  End();
5121 }
5122 
5123 bool ImGui::OpenPopupOnItemClick(const char* str_id, int mouse_button)
5124 {
5125  ImGuiWindow* window = GImGui->CurrentWindow;
5127  {
5128  ImGuiID id = str_id ? window->GetID(str_id) : window->DC.LastItemId; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict!
5129  IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
5130  OpenPopupEx(id);
5131  return true;
5132  }
5133  return false;
5134 }
5135 
5136 // This is a helper to handle the simplest case of associating one named popup to one given widget.
5137 // You may want to handle this on user side if you have specific needs (e.g. tweaking IsItemHovered() parameters).
5138 // You can pass a NULL str_id to use the identifier of the last item.
5139 bool ImGui::BeginPopupContextItem(const char* str_id, int mouse_button)
5140 {
5141  ImGuiWindow* window = GImGui->CurrentWindow;
5142  ImGuiID id = str_id ? window->GetID(str_id) : window->DC.LastItemId; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict!
5143  IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
5145  OpenPopupEx(id);
5147 }
5148 
5149 bool ImGui::BeginPopupContextWindow(const char* str_id, int mouse_button, bool also_over_items)
5150 {
5151  if (!str_id)
5152  str_id = "window_context";
5153  ImGuiID id = GImGui->CurrentWindow->GetID(str_id);
5155  if (also_over_items || !IsAnyItemHovered())
5156  OpenPopupEx(id);
5158 }
5159 
5160 bool ImGui::BeginPopupContextVoid(const char* str_id, int mouse_button)
5161 {
5162  if (!str_id)
5163  str_id = "void_context";
5164  ImGuiID id = GImGui->CurrentWindow->GetID(str_id);
5166  OpenPopupEx(id);
5168 }
5169 
5170 static bool BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags)
5171 {
5172  ImGuiContext& g = *GImGui;
5173  ImGuiWindow* parent_window = ImGui::GetCurrentWindow();
5175  flags |= (parent_window->Flags & ImGuiWindowFlags_NoMove); // Inherit the NoMove flag
5176 
5177  const ImVec2 content_avail = ImGui::GetContentRegionAvail();
5178  ImVec2 size = ImFloor(size_arg);
5179  const int auto_fit_axises = ((size.x == 0.0f) ? (1 << ImGuiAxis_X) : 0x00) | ((size.y == 0.0f) ? (1 << ImGuiAxis_Y) : 0x00);
5180  if (size.x <= 0.0f)
5181  size.x = ImMax(content_avail.x + size.x, 4.0f); // Arbitrary minimum child size (0.0f causing too much issues)
5182  if (size.y <= 0.0f)
5183  size.y = ImMax(content_avail.y + size.y, 4.0f);
5184 
5185  const float backup_border_size = g.Style.ChildBorderSize;
5186  if (!border)
5187  g.Style.ChildBorderSize = 0.0f;
5188  flags |= extra_flags;
5189 
5190  char title[256];
5191  if (name)
5192  ImFormatString(title, IM_ARRAYSIZE(title), "%s/%s", parent_window->Name, name);
5193  else
5194  ImFormatString(title, IM_ARRAYSIZE(title), "%s/%08X", parent_window->Name, id);
5195 
5197  bool ret = ImGui::Begin(title, NULL, flags);
5198  ImGuiWindow* child_window = ImGui::GetCurrentWindow();
5199  child_window->ChildId = id;
5200  child_window->AutoFitChildAxises = auto_fit_axises;
5201  g.Style.ChildBorderSize = backup_border_size;
5202 
5203  // Process navigation-in immediately so NavInit can run on first frame
5204  if (!(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayerActiveMask != 0 || child_window->DC.NavHasScroll) && g.NavActivateId == id)
5205  {
5206  ImGui::FocusWindow(child_window);
5207  ImGui::NavInitWindow(child_window, false);
5208  ImGui::SetActiveID(id+1, child_window); // Steal ActiveId with a dummy id so that key-press won't activate child item
5210  }
5211 
5212  return ret;
5213 }
5214 
5215 bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags)
5216 {
5217  ImGuiWindow* window = GetCurrentWindow();
5218  return BeginChildEx(str_id, window->GetID(str_id), size_arg, border, extra_flags);
5219 }
5220 
5221 bool ImGui::BeginChild(ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags)
5222 {
5223  IM_ASSERT(id != 0);
5224  return BeginChildEx(NULL, id, size_arg, border, extra_flags);
5225 }
5226 
5228 {
5229  ImGuiContext& g = *GImGui;
5230  ImGuiWindow* window = g.CurrentWindow;
5231 
5232  IM_ASSERT(window->Flags & ImGuiWindowFlags_ChildWindow); // Mismatched BeginChild()/EndChild() callss
5233  if (window->BeginCount > 1)
5234  {
5235  End();
5236  }
5237  else
5238  {
5239  ImVec2 sz = window->Size;
5240  if (window->AutoFitChildAxises & (1 << ImGuiAxis_X)) // Arbitrary minimum zero-ish child size of 4.0f causes less trouble than a 0.0f
5241  sz.x = ImMax(4.0f, sz.x);
5242  if (window->AutoFitChildAxises & (1 << ImGuiAxis_Y))
5243  sz.y = ImMax(4.0f, sz.y);
5244  End();
5245 
5246  ImGuiWindow* parent_window = g.CurrentWindow;
5247  ImRect bb(parent_window->DC.CursorPos, parent_window->DC.CursorPos + sz);
5248  ItemSize(sz);
5249  if ((window->DC.NavLayerActiveMask != 0 || window->DC.NavHasScroll) && !(window->Flags & ImGuiWindowFlags_NavFlattened))
5250  {
5251  ItemAdd(bb, window->ChildId);
5252  RenderNavHighlight(bb, window->ChildId);
5253 
5254  // When browsing a window that has no activable items (scroll only) we keep a highlight on the child
5255  if (window->DC.NavLayerActiveMask == 0 && window == g.NavWindow)
5257  }
5258  else
5259  {
5260  // Not navigable into
5261  ItemAdd(bb, 0);
5262  }
5263  }
5264 }
5265 
5266 // Helper to create a child window / scrolling region that looks like a normal widget frame.
5267 bool ImGui::BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags extra_flags)
5268 {
5269  ImGuiContext& g = *GImGui;
5270  const ImGuiStyle& style = g.Style;
5275  return BeginChild(id, size, true, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysUseWindowPadding | extra_flags);
5276 }
5277 
5279 {
5280  EndChild();
5281  PopStyleVar(3);
5282  PopStyleColor();
5283 }
5284 
5285 // Save and compare stack sizes on Begin()/End() to detect usage errors
5286 static void CheckStacksSize(ImGuiWindow* window, bool write)
5287 {
5288  // NOT checking: DC.ItemWidth, DC.AllowKeyboardFocus, DC.ButtonRepeat, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin)
5289  ImGuiContext& g = *GImGui;
5290  int* p_backup = &window->DC.StackSizesBackup[0];
5291  { int current = window->IDStack.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current && "PushID/PopID or TreeNode/TreePop Mismatch!"); p_backup++; } // Too few or too many PopID()/TreePop()
5292  { int current = window->DC.GroupStack.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current && "BeginGroup/EndGroup Mismatch!"); p_backup++; } // Too few or too many EndGroup()
5293  { int current = g.CurrentPopupStack.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current && "BeginMenu/EndMenu or BeginPopup/EndPopup Mismatch"); p_backup++;}// Too few or too many EndMenu()/EndPopup()
5294  // For color, style and font stacks there is an incentive to use Push/Begin/Pop/.../End patterns, so we relax our checks a little to allow them.
5295  { int current = g.ColorModifiers.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup >= current && "PushStyleColor/PopStyleColor Mismatch!"); p_backup++; } // Too few or too many PopStyleColor()
5296  { int current = g.StyleModifiers.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup >= current && "PushStyleVar/PopStyleVar Mismatch!"); p_backup++; } // Too few or too many PopStyleVar()
5297  { int current = g.FontStack.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup >= current && "PushFont/PopFont Mismatch!"); p_backup++; } // Too few or too many PopFont()
5298  IM_ASSERT(p_backup == window->DC.StackSizesBackup + IM_ARRAYSIZE(window->DC.StackSizesBackup));
5299 }
5300 
5302 {
5305 };
5306 
5307 static ImRect FindAllowedExtentRectForWindow(ImGuiWindow*)
5308 {
5309  ImVec2 padding = GImGui->Style.DisplaySafeAreaPadding;
5310  ImRect r_screen = GetViewportRect();
5311  r_screen.Expand(ImVec2((r_screen.GetWidth() > padding.x * 2) ? -padding.x : 0.0f, (r_screen.GetHeight() > padding.y * 2) ? -padding.y : 0.0f));
5312  return r_screen;
5313 }
5314 
5315 // r_avoid = the rectangle to avoid (e.g. for tooltip it is a rectangle around the mouse cursor which we want to avoid. for popups it's a small point around the cursor.)
5316 // r_outer = the visible area rectangle, minus safe area padding. If our popup size won't fit because of safe area padding we ignore it.
5317 static ImVec2 FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy = ImGuiPopupPositionPolicy_Default)
5318 {
5319  ImVec2 base_pos_clamped = ImClamp(ref_pos, r_outer.Min, r_outer.Max - size);
5320  //GImGui->OverlayDrawList.AddRect(r_avoid.Min, r_avoid.Max, IM_COL32(255,0,0,255));
5321  //GImGui->OverlayDrawList.AddRect(r_outer.Min, r_outer.Max, IM_COL32(0,255,0,255));
5322 
5323  // Combo Box policy (we want a connecting edge)
5324  if (policy == ImGuiPopupPositionPolicy_ComboBox)
5325  {
5326  const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Down, ImGuiDir_Right, ImGuiDir_Left, ImGuiDir_Up };
5327  for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++)
5328  {
5329  const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n];
5330  if (n != -1 && dir == *last_dir) // Already tried this direction?
5331  continue;
5332  ImVec2 pos;
5333  if (dir == ImGuiDir_Down) pos = ImVec2(r_avoid.Min.x, r_avoid.Max.y); // Below, Toward Right (default)
5334  if (dir == ImGuiDir_Right) pos = ImVec2(r_avoid.Min.x, r_avoid.Min.y - size.y); // Above, Toward Right
5335  if (dir == ImGuiDir_Left) pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Max.y); // Below, Toward Left
5336  if (dir == ImGuiDir_Up) pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Min.y - size.y); // Above, Toward Left
5337  if (!r_outer.Contains(ImRect(pos, pos + size)))
5338  continue;
5339  *last_dir = dir;
5340  return pos;
5341  }
5342  }
5343 
5344  // Default popup policy
5345  const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Right, ImGuiDir_Down, ImGuiDir_Up, ImGuiDir_Left };
5346  for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++)
5347  {
5348  const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n];
5349  if (n != -1 && dir == *last_dir) // Already tried this direction?
5350  continue;
5351  float avail_w = (dir == ImGuiDir_Left ? r_avoid.Min.x : r_outer.Max.x) - (dir == ImGuiDir_Right ? r_avoid.Max.x : r_outer.Min.x);
5352  float avail_h = (dir == ImGuiDir_Up ? r_avoid.Min.y : r_outer.Max.y) - (dir == ImGuiDir_Down ? r_avoid.Max.y : r_outer.Min.y);
5353  if (avail_w < size.x || avail_h < size.y)
5354  continue;
5355  ImVec2 pos;
5356  pos.x = (dir == ImGuiDir_Left) ? r_avoid.Min.x - size.x : (dir == ImGuiDir_Right) ? r_avoid.Max.x : base_pos_clamped.x;
5357  pos.y = (dir == ImGuiDir_Up) ? r_avoid.Min.y - size.y : (dir == ImGuiDir_Down) ? r_avoid.Max.y : base_pos_clamped.y;
5358  *last_dir = dir;
5359  return pos;
5360  }
5361 
5362  // Fallback, try to keep within display
5363  *last_dir = ImGuiDir_None;
5364  ImVec2 pos = ref_pos;
5365  pos.x = ImMax(ImMin(pos.x + size.x, r_outer.Max.x) - size.x, r_outer.Min.x);
5366  pos.y = ImMax(ImMin(pos.y + size.y, r_outer.Max.y) - size.y, r_outer.Min.y);
5367  return pos;
5368 }
5369 
5370 static ImVec2 FindBestWindowPosForPopup(ImGuiWindow* window)
5371 {
5372  ImGuiContext& g = *GImGui;
5373 
5374  ImRect r_outer = FindAllowedExtentRectForWindow(window);
5375  if (window->Flags & ImGuiWindowFlags_ChildMenu)
5376  {
5377  // Child menus typically request _any_ position within the parent menu item, and then our FindBestWindowPosForPopup() function will move the new menu outside the parent bounds.
5378  // This is how we end up with child menus appearing (most-commonly) on the right of the parent menu.
5379  IM_ASSERT(g.CurrentWindow == window);
5380  ImGuiWindow* parent_window = g.CurrentWindowStack[g.CurrentWindowStack.Size - 2];
5381  float horizontal_overlap = g.Style.ItemSpacing.x; // We want some overlap to convey the relative depth of each menu (currently the amount of overlap is hard-coded to style.ItemSpacing.x).
5382  ImRect r_avoid;
5383  if (parent_window->DC.MenuBarAppending)
5384  r_avoid = ImRect(-FLT_MAX, parent_window->Pos.y + parent_window->TitleBarHeight(), FLT_MAX, parent_window->Pos.y + parent_window->TitleBarHeight() + parent_window->MenuBarHeight());
5385  else
5386  r_avoid = ImRect(parent_window->Pos.x + horizontal_overlap, -FLT_MAX, parent_window->Pos.x + parent_window->Size.x - horizontal_overlap - parent_window->ScrollbarSizes.x, FLT_MAX);
5387  return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid);
5388  }
5389  if (window->Flags & ImGuiWindowFlags_Popup)
5390  {
5391  ImRect r_avoid = ImRect(window->Pos.x - 1, window->Pos.y - 1, window->Pos.x + 1, window->Pos.y + 1);
5392  return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid);
5393  }
5394  if (window->Flags & ImGuiWindowFlags_Tooltip)
5395  {
5396  // Position tooltip (always follows mouse)
5397  float sc = g.Style.MouseCursorScale;
5398  ImVec2 ref_pos = NavCalcPreferredRefPos();
5399  ImRect r_avoid;
5401  r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 16, ref_pos.y + 8);
5402  else
5403  r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 24 * sc, ref_pos.y + 24 * sc); // FIXME: Hard-coded based on mouse cursor shape expectation. Exact dimension not very important.
5404  ImVec2 pos = FindBestWindowPosForPopupEx(ref_pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid);
5405  if (window->AutoPosLastDirection == ImGuiDir_None)
5406  pos = ref_pos + ImVec2(2, 2); // If there's not enough room, for tooltip we prefer avoiding the cursor at all cost even if it means that part of the tooltip won't be visible.
5407  return pos;
5408  }
5409  IM_ASSERT(0);
5410  return window->Pos;
5411 }
5412 
5413 static void SetWindowConditionAllowFlags(ImGuiWindow* window, ImGuiCond flags, bool enabled)
5414 {
5415  window->SetWindowPosAllowFlags = enabled ? (window->SetWindowPosAllowFlags | flags) : (window->SetWindowPosAllowFlags & ~flags);
5416  window->SetWindowSizeAllowFlags = enabled ? (window->SetWindowSizeAllowFlags | flags) : (window->SetWindowSizeAllowFlags & ~flags);
5417  window->SetWindowCollapsedAllowFlags = enabled ? (window->SetWindowCollapsedAllowFlags | flags) : (window->SetWindowCollapsedAllowFlags & ~flags);
5418 }
5419 
5421 {
5422  ImGuiContext& g = *GImGui;
5423  ImGuiID id = ImHash(name, 0);
5424  return (ImGuiWindow*)g.WindowsById.GetVoidPtr(id);
5425 }
5426 
5427 static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFlags flags)
5428 {
5429  ImGuiContext& g = *GImGui;
5430 
5431  // Create window the first time
5432  ImGuiWindow* window = IM_NEW(ImGuiWindow)(&g, name);
5433  window->Flags = flags;
5434  g.WindowsById.SetVoidPtr(window->ID, window);
5435 
5436  // Default/arbitrary window position. Use SetNextWindowPos() with the appropriate condition flag to change the initial position of a window.
5437  window->Pos = ImVec2(60, 60);
5438 
5439  // User can disable loading and saving of settings. Tooltip and child windows also don't store settings.
5440  if (!(flags & ImGuiWindowFlags_NoSavedSettings))
5441  {
5442  // Retrieve settings from .ini file
5443  if (ImGuiWindowSettings* settings = ImGui::FindWindowSettings(window->ID))
5444  {
5445  SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false);
5446  window->Pos = ImFloor(settings->Pos);
5447  window->Collapsed = settings->Collapsed;
5448  if (ImLengthSqr(settings->Size) > 0.00001f)
5449  size = ImFloor(settings->Size);
5450  }
5451  }
5452  window->Size = window->SizeFull = window->SizeFullAtLastBegin = size;
5453 
5454  if ((flags & ImGuiWindowFlags_AlwaysAutoResize) != 0)
5455  {
5456  window->AutoFitFramesX = window->AutoFitFramesY = 2;
5457  window->AutoFitOnlyGrows = false;
5458  }
5459  else
5460  {
5461  if (window->Size.x <= 0.0f)
5462  window->AutoFitFramesX = 2;
5463  if (window->Size.y <= 0.0f)
5464  window->AutoFitFramesY = 2;
5465  window->AutoFitOnlyGrows = (window->AutoFitFramesX > 0) || (window->AutoFitFramesY > 0);
5466  }
5467 
5469  g.Windows.insert(g.Windows.begin(), window); // Quite slow but rare and only once
5470  else
5471  g.Windows.push_back(window);
5472  return window;
5473 }
5474 
5475 static ImVec2 CalcSizeAfterConstraint(ImGuiWindow* window, ImVec2 new_size)
5476 {
5477  ImGuiContext& g = *GImGui;
5479  {
5480  // Using -1,-1 on either X/Y axis to preserve the current size.
5482  new_size.x = (cr.Min.x >= 0 && cr.Max.x >= 0) ? ImClamp(new_size.x, cr.Min.x, cr.Max.x) : window->SizeFull.x;
5483  new_size.y = (cr.Min.y >= 0 && cr.Max.y >= 0) ? ImClamp(new_size.y, cr.Min.y, cr.Max.y) : window->SizeFull.y;
5485  {
5488  data.Pos = window->Pos;
5489  data.CurrentSize = window->SizeFull;
5490  data.DesiredSize = new_size;
5491  g.NextWindowData.SizeCallback(&data);
5492  new_size = data.DesiredSize;
5493  }
5494  }
5495 
5496  // Minimum size
5497  if (!(window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_AlwaysAutoResize)))
5498  {
5499  new_size = ImMax(new_size, g.Style.WindowMinSize);
5500  new_size.y = ImMax(new_size.y, window->TitleBarHeight() + window->MenuBarHeight() + ImMax(0.0f, g.Style.WindowRounding - 1.0f)); // Reduce artifacts with very small windows
5501  }
5502  return new_size;
5503 }
5504 
5505 static ImVec2 CalcSizeContents(ImGuiWindow* window)
5506 {
5507  ImVec2 sz;
5508  sz.x = (float)(int)((window->SizeContentsExplicit.x != 0.0f) ? window->SizeContentsExplicit.x : (window->DC.CursorMaxPos.x - window->Pos.x + window->Scroll.x));
5509  sz.y = (float)(int)((window->SizeContentsExplicit.y != 0.0f) ? window->SizeContentsExplicit.y : (window->DC.CursorMaxPos.y - window->Pos.y + window->Scroll.y));
5510  return sz + window->WindowPadding;
5511 }
5512 
5513 static ImVec2 CalcSizeAutoFit(ImGuiWindow* window, const ImVec2& size_contents)
5514 {
5515  ImGuiContext& g = *GImGui;
5516  ImGuiStyle& style = g.Style;
5517  if (window->Flags & ImGuiWindowFlags_Tooltip)
5518  {
5519  // Tooltip always resize
5520  return size_contents;
5521  }
5522  else
5523  {
5524  // When the window cannot fit all contents (either because of constraints, either because screen is too small): we are growing the size on the other axis to compensate for expected scrollbar. FIXME: Might turn bigger than DisplaySize-WindowPadding.
5525  ImVec2 size_auto_fit = ImClamp(size_contents, style.WindowMinSize, ImMax(style.WindowMinSize, g.IO.DisplaySize - g.Style.DisplaySafeAreaPadding * 2.0f));
5526  ImVec2 size_auto_fit_after_constraint = CalcSizeAfterConstraint(window, size_auto_fit);
5527  if (size_auto_fit_after_constraint.x < size_contents.x && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar))
5528  size_auto_fit.y += style.ScrollbarSize;
5529  if (size_auto_fit_after_constraint.y < size_contents.y && !(window->Flags & ImGuiWindowFlags_NoScrollbar))
5530  size_auto_fit.x += style.ScrollbarSize;
5531  return size_auto_fit;
5532  }
5533 }
5534 
5535 static float GetScrollMaxX(ImGuiWindow* window)
5536 {
5537  return ImMax(0.0f, window->SizeContents.x - (window->SizeFull.x - window->ScrollbarSizes.x));
5538 }
5539 
5540 static float GetScrollMaxY(ImGuiWindow* window)
5541 {
5542  return ImMax(0.0f, window->SizeContents.y - (window->SizeFull.y - window->ScrollbarSizes.y));
5543 }
5544 
5545 static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool snap_on_edges)
5546 {
5547  ImGuiContext& g = *GImGui;
5548  ImVec2 scroll = window->Scroll;
5549  if (window->ScrollTarget.x < FLT_MAX)
5550  {
5551  float cr_x = window->ScrollTargetCenterRatio.x;
5552  scroll.x = window->ScrollTarget.x - cr_x * (window->SizeFull.x - window->ScrollbarSizes.x);
5553  }
5554  if (window->ScrollTarget.y < FLT_MAX)
5555  {
5556  // 'snap_on_edges' allows for a discontinuity at the edge of scrolling limits to take account of WindowPadding so that scrolling to make the last item visible scroll far enough to see the padding.
5557  float cr_y = window->ScrollTargetCenterRatio.y;
5558  float target_y = window->ScrollTarget.y;
5559  if (snap_on_edges && cr_y <= 0.0f && target_y <= window->WindowPadding.y)
5560  target_y = 0.0f;
5561  if (snap_on_edges && cr_y >= 1.0f && target_y >= window->SizeContents.y - window->WindowPadding.y + g.Style.ItemSpacing.y)
5562  target_y = window->SizeContents.y;
5563  scroll.y = target_y - (1.0f - cr_y) * (window->TitleBarHeight() + window->MenuBarHeight()) - cr_y * (window->SizeFull.y - window->ScrollbarSizes.y);
5564  }
5565  scroll = ImMax(scroll, ImVec2(0.0f, 0.0f));
5566  if (!window->Collapsed && !window->SkipItems)
5567  {
5568  scroll.x = ImMin(scroll.x, GetScrollMaxX(window));
5569  scroll.y = ImMin(scroll.y, GetScrollMaxY(window));
5570  }
5571  return scroll;
5572 }
5573 
5574 static ImGuiCol GetWindowBgColorIdxFromFlags(ImGuiWindowFlags flags)
5575 {
5577  return ImGuiCol_PopupBg;
5578  if (flags & ImGuiWindowFlags_ChildWindow)
5579  return ImGuiCol_ChildBg;
5580  return ImGuiCol_WindowBg;
5581 }
5582 
5583 static void CalcResizePosSizeFromAnyCorner(ImGuiWindow* window, const ImVec2& corner_target, const ImVec2& corner_norm, ImVec2* out_pos, ImVec2* out_size)
5584 {
5585  ImVec2 pos_min = ImLerp(corner_target, window->Pos, corner_norm); // Expected window upper-left
5586  ImVec2 pos_max = ImLerp(window->Pos + window->Size, corner_target, corner_norm); // Expected window lower-right
5587  ImVec2 size_expected = pos_max - pos_min;
5588  ImVec2 size_constrained = CalcSizeAfterConstraint(window, size_expected);
5589  *out_pos = pos_min;
5590  if (corner_norm.x == 0.0f)
5591  out_pos->x -= (size_constrained.x - size_expected.x);
5592  if (corner_norm.y == 0.0f)
5593  out_pos->y -= (size_constrained.y - size_expected.y);
5594  *out_size = size_constrained;
5595 }
5596 
5598 {
5602 };
5603 
5605 {
5606  { ImVec2(1,1), ImVec2(-1,-1), 0, 3 }, // Lower right
5607  { ImVec2(0,1), ImVec2(+1,-1), 3, 6 }, // Lower left
5608  { ImVec2(0,0), ImVec2(+1,+1), 6, 9 }, // Upper left
5609  { ImVec2(1,0), ImVec2(-1,+1), 9,12 }, // Upper right
5610 };
5611 
5612 static ImRect GetBorderRect(ImGuiWindow* window, int border_n, float perp_padding, float thickness)
5613 {
5614  ImRect rect = window->Rect();
5615  if (thickness == 0.0f) rect.Max -= ImVec2(1,1);
5616  if (border_n == 0) return ImRect(rect.Min.x + perp_padding, rect.Min.y, rect.Max.x - perp_padding, rect.Min.y + thickness);
5617  if (border_n == 1) return ImRect(rect.Max.x - thickness, rect.Min.y + perp_padding, rect.Max.x, rect.Max.y - perp_padding);
5618  if (border_n == 2) return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness, rect.Max.x - perp_padding, rect.Max.y);
5619  if (border_n == 3) return ImRect(rect.Min.x, rect.Min.y + perp_padding, rect.Min.x + thickness, rect.Max.y - perp_padding);
5620  IM_ASSERT(0);
5621  return ImRect();
5622 }
5623 
5624 // Handle resize for: Resize Grips, Borders, Gamepad
5625 static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4])
5626 {
5627  ImGuiContext& g = *GImGui;
5628  ImGuiWindowFlags flags = window->Flags;
5629  if ((flags & ImGuiWindowFlags_NoResize) || (flags & ImGuiWindowFlags_AlwaysAutoResize) || window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0)
5630  return;
5631 
5632  const int resize_border_count = (flags & ImGuiWindowFlags_ResizeFromAnySide) ? 4 : 0;
5633  const float grip_draw_size = (float)(int)ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f);
5634  const float grip_hover_size = (float)(int)(grip_draw_size * 0.75f);
5635 
5636  ImVec2 pos_target(FLT_MAX, FLT_MAX);
5637  ImVec2 size_target(FLT_MAX, FLT_MAX);
5638 
5639  // Manual resize grips
5640  PushID("#RESIZE");
5641  for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++)
5642  {
5643  const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n];
5644  const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPos);
5645 
5646  // Using the FlattenChilds button flag we make the resize button accessible even if we are hovering over a child window
5647  ImRect resize_rect(corner, corner + grip.InnerDir * grip_hover_size);
5648  if (resize_rect.Min.x > resize_rect.Max.x) ImSwap(resize_rect.Min.x, resize_rect.Max.x);
5649  if (resize_rect.Min.y > resize_rect.Max.y) ImSwap(resize_rect.Min.y, resize_rect.Max.y);
5650  bool hovered, held;
5651  ButtonBehavior(resize_rect, window->GetID((void*)(intptr_t)resize_grip_n), &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus);
5652  if (hovered || held)
5654 
5655  if (g.HoveredWindow == window && held && g.IO.MouseDoubleClicked[0] && resize_grip_n == 0)
5656  {
5657  // Manual auto-fit when double-clicking
5658  size_target = CalcSizeAfterConstraint(window, size_auto_fit);
5659  ClearActiveID();
5660  }
5661  else if (held)
5662  {
5663  // Resize from any of the four corners
5664  // We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position
5665  ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + resize_rect.GetSize() * grip.CornerPos; // Corner of the window corresponding to our corner grip
5666  CalcResizePosSizeFromAnyCorner(window, corner_target, grip.CornerPos, &pos_target, &size_target);
5667  }
5668  if (resize_grip_n == 0 || held || hovered)
5669  resize_grip_col[resize_grip_n] = GetColorU32(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip);
5670  }
5671  for (int border_n = 0; border_n < resize_border_count; border_n++)
5672  {
5673  const float BORDER_SIZE = 5.0f; // FIXME: Only works _inside_ window because of HoveredWindow check.
5674  const float BORDER_APPEAR_TIMER = 0.05f; // Reduce visual noise
5675  bool hovered, held;
5676  ImRect border_rect = GetBorderRect(window, border_n, grip_hover_size, BORDER_SIZE);
5677  ButtonBehavior(border_rect, window->GetID((void*)(intptr_t)(border_n + 4)), &hovered, &held, ImGuiButtonFlags_FlattenChildren);
5678  if ((hovered && g.HoveredIdTimer > BORDER_APPEAR_TIMER) || held)
5679  {
5681  if (held) *border_held = border_n;
5682  }
5683  if (held)
5684  {
5685  ImVec2 border_target = window->Pos;
5686  ImVec2 border_posn;
5687  if (border_n == 0) { border_posn = ImVec2(0, 0); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y); }
5688  if (border_n == 1) { border_posn = ImVec2(1, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + BORDER_SIZE); }
5689  if (border_n == 2) { border_posn = ImVec2(0, 1); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + BORDER_SIZE); }
5690  if (border_n == 3) { border_posn = ImVec2(0, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x); }
5691  CalcResizePosSizeFromAnyCorner(window, border_target, border_posn, &pos_target, &size_target);
5692  }
5693  }
5694  PopID();
5695 
5696  // Navigation resize (keyboard/gamepad)
5697  if (g.NavWindowingTarget == window)
5698  {
5699  ImVec2 nav_resize_delta;
5704  if (nav_resize_delta.x != 0.0f || nav_resize_delta.y != 0.0f)
5705  {
5706  const float NAV_RESIZE_SPEED = 600.0f;
5707  nav_resize_delta *= ImFloor(NAV_RESIZE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y));
5708  g.NavWindowingToggleLayer = false;
5709  g.NavDisableMouseHover = true;
5710  resize_grip_col[0] = GetColorU32(ImGuiCol_ResizeGripActive);
5711  // FIXME-NAV: Should store and accumulate into a separate size buffer to handle sizing constraints properly, right now a constraint will make us stuck.
5712  size_target = CalcSizeAfterConstraint(window, window->SizeFull + nav_resize_delta);
5713  }
5714  }
5715 
5716  // Apply back modified position/size to window
5717  if (size_target.x != FLT_MAX)
5718  {
5719  window->SizeFull = size_target;
5720  MarkIniSettingsDirty(window);
5721  }
5722  if (pos_target.x != FLT_MAX)
5723  {
5724  window->Pos = ImFloor(pos_target);
5725  MarkIniSettingsDirty(window);
5726  }
5727 
5728  window->Size = window->SizeFull;
5729 }
5730 
5731 // Push a new ImGui window to add widgets to.
5732 // - A default window called "Debug" is automatically stacked at the beginning of every frame so you can use widgets without explicitly calling a Begin/End pair.
5733 // - Begin/End can be called multiple times during the frame with the same window name to append content.
5734 // - The window name is used as a unique identifier to preserve window information across frames (and save rudimentary information to the .ini file).
5735 // You can use the "##" or "###" markers to use the same label with different id, or same id with different label. See documentation at the top of this file.
5736 // - Return false when window is collapsed, so you can early out in your code. You always need to call ImGui::End() even if false is returned.
5737 // - Passing 'bool* p_open' displays a Close button on the upper-right corner of the window, the pointed value will be set to false when the button is pressed.
5738 bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
5739 {
5740  ImGuiContext& g = *GImGui;
5741  const ImGuiStyle& style = g.Style;
5742  IM_ASSERT(name != NULL); // Window name required
5743  IM_ASSERT(g.Initialized); // Forgot to call ImGui::NewFrame()
5744  IM_ASSERT(g.FrameCountEnded != g.FrameCount); // Called ImGui::Render() or ImGui::EndFrame() and haven't called ImGui::NewFrame() again yet
5745 
5746  // Find or create
5747  ImGuiWindow* window = FindWindowByName(name);
5748  const bool window_just_created = (window == NULL);
5749  if (window_just_created)
5750  {
5751  ImVec2 size_on_first_use = (g.NextWindowData.SizeCond != 0) ? g.NextWindowData.SizeVal : ImVec2(0.0f, 0.0f); // Any condition flag will do since we are creating a new window here.
5752  window = CreateNewWindow(name, size_on_first_use, flags);
5753  }
5754 
5755  // Automatically disable manual moving/resizing when NoInputs is set
5756  if (flags & ImGuiWindowFlags_NoInputs)
5758 
5759  if (flags & ImGuiWindowFlags_NavFlattened)
5761 
5762  const int current_frame = g.FrameCount;
5763  const bool first_begin_of_the_frame = (window->LastFrameActive != current_frame);
5764  if (first_begin_of_the_frame)
5765  window->Flags = (ImGuiWindowFlags)flags;
5766  else
5767  flags = window->Flags;
5768 
5769  // Update the Appearing flag
5770  bool window_just_activated_by_user = (window->LastFrameActive < current_frame - 1); // Not using !WasActive because the implicit "Debug" window would always toggle off->on
5771  const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFrames > 0);
5772  if (flags & ImGuiWindowFlags_Popup)
5773  {
5775  window_just_activated_by_user |= (window->PopupId != popup_ref.PopupId); // We recycle popups so treat window as activated if popup id changed
5776  window_just_activated_by_user |= (window != popup_ref.Window);
5777  }
5778  window->Appearing = (window_just_activated_by_user || window_just_appearing_after_hidden_for_resize);
5779  window->CloseButton = (p_open != NULL);
5780  if (window->Appearing)
5781  SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, true);
5782 
5783  // Parent window is latched only on the first call to Begin() of the frame, so further append-calls can be done from a different window stack
5784  ImGuiWindow* parent_window_in_stack = g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back();
5785  ImGuiWindow* parent_window = first_begin_of_the_frame ? ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)) ? parent_window_in_stack : NULL) : window->ParentWindow;
5786  IM_ASSERT(parent_window != NULL || !(flags & ImGuiWindowFlags_ChildWindow));
5787 
5788  // Add to stack
5789  g.CurrentWindowStack.push_back(window);
5790  SetCurrentWindow(window);
5791  CheckStacksSize(window, true);
5792  if (flags & ImGuiWindowFlags_Popup)
5793  {
5795  popup_ref.Window = window;
5796  g.CurrentPopupStack.push_back(popup_ref);
5797  window->PopupId = popup_ref.PopupId;
5798  }
5799 
5800  if (window_just_appearing_after_hidden_for_resize && !(flags & ImGuiWindowFlags_ChildWindow))
5801  window->NavLastIds[0] = 0;
5802 
5803  // Process SetNextWindow***() calls
5804  bool window_pos_set_by_api = false;
5805  bool window_size_x_set_by_api = false, window_size_y_set_by_api = false;
5806  if (g.NextWindowData.PosCond)
5807  {
5808  window_pos_set_by_api = (window->SetWindowPosAllowFlags & g.NextWindowData.PosCond) != 0;
5809  if (window_pos_set_by_api && ImLengthSqr(g.NextWindowData.PosPivotVal) > 0.00001f)
5810  {
5811  // May be processed on the next frame if this is our first frame and we are measuring size
5812  // FIXME: Look into removing the branch so everything can go through this same code path for consistency.
5816  }
5817  else
5818  {
5820  }
5821  }
5822  if (g.NextWindowData.SizeCond)
5823  {
5824  window_size_x_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.x > 0.0f);
5825  window_size_y_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.y > 0.0f);
5827  }
5829  {
5830  // Adjust passed "client size" to become a "window size"
5832  if (window->SizeContentsExplicit.y != 0.0f)
5833  window->SizeContentsExplicit.y += window->TitleBarHeight() + window->MenuBarHeight();
5834  }
5835  else if (first_begin_of_the_frame)
5836  {
5837  window->SizeContentsExplicit = ImVec2(0.0f, 0.0f);
5838  }
5841  if (g.NextWindowData.FocusCond)
5842  FocusWindow(window);
5843  if (window->Appearing)
5844  SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, false);
5845 
5846  // When reusing window again multiple times a frame, just append content (don't need to setup again)
5847  if (first_begin_of_the_frame)
5848  {
5849  const bool window_is_child_tooltip = (flags & ImGuiWindowFlags_ChildWindow) && (flags & ImGuiWindowFlags_Tooltip); // FIXME-WIP: Undocumented behavior of Child+Tooltip for pinned tooltip (#1345)
5850 
5851  // Initialize
5852  window->ParentWindow = parent_window;
5853  window->RootWindow = window->RootWindowForTitleBarHighlight = window->RootWindowForTabbing = window->RootWindowForNav = window;
5854  if (parent_window && (flags & ImGuiWindowFlags_ChildWindow) && !window_is_child_tooltip)
5855  window->RootWindow = parent_window->RootWindow;
5856  if (parent_window && !(flags & ImGuiWindowFlags_Modal) && (flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)))
5857  window->RootWindowForTitleBarHighlight = window->RootWindowForTabbing = parent_window->RootWindowForTitleBarHighlight; // Same value in master branch, will differ for docking
5858  while (window->RootWindowForNav->Flags & ImGuiWindowFlags_NavFlattened)
5859  window->RootWindowForNav = window->RootWindowForNav->ParentWindow;
5860 
5861  window->Active = true;
5862  window->BeginOrderWithinParent = 0;
5864  window->BeginCount = 0;
5865  window->ClipRect = ImVec4(-FLT_MAX,-FLT_MAX,+FLT_MAX,+FLT_MAX);
5866  window->LastFrameActive = current_frame;
5867  window->IDStack.resize(1);
5868 
5869  // UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS
5870 
5871  // Update contents size from last frame for auto-fitting (or use explicit size)
5872  window->SizeContents = CalcSizeContents(window);
5873  if (window->HiddenFrames > 0)
5874  window->HiddenFrames--;
5875 
5876  // Hide new windows for one frame until they calculate their size
5877  if (window_just_created && (!window_size_x_set_by_api || !window_size_y_set_by_api))
5878  window->HiddenFrames = 1;
5879 
5880  // Hide popup/tooltip window when re-opening while we measure size (because we recycle the windows)
5881  // We reset Size/SizeContents for reappearing popups/tooltips early in this function, so further code won't be tempted to use the old size.
5882  if (window_just_activated_by_user && (flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) != 0)
5883  {
5884  window->HiddenFrames = 1;
5885  if (flags & ImGuiWindowFlags_AlwaysAutoResize)
5886  {
5887  if (!window_size_x_set_by_api)
5888  window->Size.x = window->SizeFull.x = 0.f;
5889  if (!window_size_y_set_by_api)
5890  window->Size.y = window->SizeFull.y = 0.f;
5891  window->SizeContents = ImVec2(0.f, 0.f);
5892  }
5893  }
5894 
5895  SetCurrentWindow(window);
5896 
5897  // Lock border size and padding for the frame (so that altering them doesn't cause inconsistencies)
5898  window->WindowBorderSize = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildBorderSize : ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupBorderSize : style.WindowBorderSize;
5899  window->WindowPadding = style.WindowPadding;
5900  if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & (ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_Popup)) && window->WindowBorderSize == 0.0f)
5901  window->WindowPadding = ImVec2(0.0f, (flags & ImGuiWindowFlags_MenuBar) ? style.WindowPadding.y : 0.0f);
5902  window->DC.MenuBarOffset.x = ImMax(ImMax(window->WindowPadding.x, style.ItemSpacing.x), g.NextWindowData.MenuBarOffsetMinVal.x);
5904 
5905  // Collapse window by double-clicking on title bar
5906  // At this point we don't have a clipping rectangle setup yet, so we can use the title bar area for hit detection and drawing
5907  if (!(flags & ImGuiWindowFlags_NoTitleBar) && !(flags & ImGuiWindowFlags_NoCollapse))
5908  {
5909  ImRect title_bar_rect = window->TitleBarRect();
5910  if (window->CollapseToggleWanted || (g.HoveredWindow == window && IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max) && g.IO.MouseDoubleClicked[0]))
5911  {
5912  window->Collapsed = !window->Collapsed;
5913  MarkIniSettingsDirty(window);
5914  FocusWindow(window);
5915  }
5916  }
5917  else
5918  {
5919  window->Collapsed = false;
5920  }
5921  window->CollapseToggleWanted = false;
5922 
5923  // SIZE
5924 
5925  // Calculate auto-fit size, handle automatic resize
5926  const ImVec2 size_auto_fit = CalcSizeAutoFit(window, window->SizeContents);
5927  ImVec2 size_full_modified(FLT_MAX, FLT_MAX);
5928  if ((flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed)
5929  {
5930  // Using SetNextWindowSize() overrides ImGuiWindowFlags_AlwaysAutoResize, so it can be used on tooltips/popups, etc.
5931  if (!window_size_x_set_by_api)
5932  window->SizeFull.x = size_full_modified.x = size_auto_fit.x;
5933  if (!window_size_y_set_by_api)
5934  window->SizeFull.y = size_full_modified.y = size_auto_fit.y;
5935  }
5936  else if (window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0)
5937  {
5938  // Auto-fit may only grow window during the first few frames
5939  // We still process initial auto-fit on collapsed windows to get a window width, but otherwise don't honor ImGuiWindowFlags_AlwaysAutoResize when collapsed.
5940  if (!window_size_x_set_by_api && window->AutoFitFramesX > 0)
5941  window->SizeFull.x = size_full_modified.x = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.x, size_auto_fit.x) : size_auto_fit.x;
5942  if (!window_size_y_set_by_api && window->AutoFitFramesY > 0)
5943  window->SizeFull.y = size_full_modified.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y;
5944  if (!window->Collapsed)
5945  MarkIniSettingsDirty(window);
5946  }
5947 
5948  // Apply minimum/maximum window size constraints and final size
5949  window->SizeFull = CalcSizeAfterConstraint(window, window->SizeFull);
5950  window->Size = window->Collapsed && !(flags & ImGuiWindowFlags_ChildWindow) ? window->TitleBarRect().GetSize() : window->SizeFull;
5951 
5952  // SCROLLBAR STATUS
5953 
5954  // Update scrollbar status (based on the Size that was effective during last frame or the auto-resized Size).
5955  if (!window->Collapsed)
5956  {
5957  // When reading the current size we need to read it after size constraints have been applied
5958  float size_x_for_scrollbars = size_full_modified.x != FLT_MAX ? window->SizeFull.x : window->SizeFullAtLastBegin.x;
5959  float size_y_for_scrollbars = size_full_modified.y != FLT_MAX ? window->SizeFull.y : window->SizeFullAtLastBegin.y;
5960  window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((window->SizeContents.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar));
5961  window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((window->SizeContents.x > size_x_for_scrollbars - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar));
5962  if (window->ScrollbarX && !window->ScrollbarY)
5963  window->ScrollbarY = (window->SizeContents.y > size_y_for_scrollbars - style.ScrollbarSize) && !(flags & ImGuiWindowFlags_NoScrollbar);
5964  window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f);
5965  }
5966 
5967  // POSITION
5968 
5969  // Popup latch its initial position, will position itself when it appears next frame
5970  if (window_just_activated_by_user)
5971  {
5973  if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api)
5974  window->Pos = g.CurrentPopupStack.back().OpenPopupPos;
5975  }
5976 
5977  // Position child window
5978  if (flags & ImGuiWindowFlags_ChildWindow)
5979  {
5980  window->BeginOrderWithinParent = parent_window->DC.ChildWindows.Size;
5981  parent_window->DC.ChildWindows.push_back(window);
5982  if (!(flags & ImGuiWindowFlags_Popup) && !window_pos_set_by_api && !window_is_child_tooltip)
5983  window->Pos = parent_window->DC.CursorPos;
5984  }
5985 
5986  const bool window_pos_with_pivot = (window->SetWindowPosVal.x != FLT_MAX && window->HiddenFrames == 0);
5987  if (window_pos_with_pivot)
5988  SetWindowPos(window, ImMax(style.DisplaySafeAreaPadding, window->SetWindowPosVal - window->SizeFull * window->SetWindowPosPivot), 0); // Position given a pivot (e.g. for centering)
5989  else if ((flags & ImGuiWindowFlags_ChildMenu) != 0)
5990  window->Pos = FindBestWindowPosForPopup(window);
5991  else if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api && window_just_appearing_after_hidden_for_resize)
5992  window->Pos = FindBestWindowPosForPopup(window);
5993  else if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_pos_set_by_api && !window_is_child_tooltip)
5994  window->Pos = FindBestWindowPosForPopup(window);
5995 
5996  // Clamp position so it stays visible
5997  if (!(flags & ImGuiWindowFlags_ChildWindow))
5998  {
5999  if (!window_pos_set_by_api && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0 && g.IO.DisplaySize.x > 0.0f && g.IO.DisplaySize.y > 0.0f) // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing.
6000  {
6001  ImVec2 padding = ImMax(style.DisplayWindowPadding, style.DisplaySafeAreaPadding);
6002  window->Pos = ImMax(window->Pos + window->Size, padding) - window->Size;
6003  window->Pos = ImMin(window->Pos, g.IO.DisplaySize - padding);
6004  }
6005  }
6006  window->Pos = ImFloor(window->Pos);
6007 
6008  // Lock window rounding for the frame (so that altering them doesn't cause inconsistencies)
6009  window->WindowRounding = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildRounding : ((flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupRounding : style.WindowRounding;
6010 
6011  // Prepare for focus requests
6012  window->FocusIdxAllRequestCurrent = (window->FocusIdxAllRequestNext == INT_MAX || window->FocusIdxAllCounter == -1) ? INT_MAX : (window->FocusIdxAllRequestNext + (window->FocusIdxAllCounter+1)) % (window->FocusIdxAllCounter+1);
6013  window->FocusIdxTabRequestCurrent = (window->FocusIdxTabRequestNext == INT_MAX || window->FocusIdxTabCounter == -1) ? INT_MAX : (window->FocusIdxTabRequestNext + (window->FocusIdxTabCounter+1)) % (window->FocusIdxTabCounter+1);
6014  window->FocusIdxAllCounter = window->FocusIdxTabCounter = -1;
6015  window->FocusIdxAllRequestNext = window->FocusIdxTabRequestNext = INT_MAX;
6016 
6017  // Apply scrolling
6018  window->Scroll = CalcNextScrollFromScrollTargetAndClamp(window, true);
6019  window->ScrollTarget = ImVec2(FLT_MAX, FLT_MAX);
6020 
6021  // Apply focus, new windows appears in front
6022  bool want_focus = false;
6023  if (window_just_activated_by_user && !(flags & ImGuiWindowFlags_NoFocusOnAppearing))
6024  if (!(flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Tooltip)) || (flags & ImGuiWindowFlags_Popup))
6025  want_focus = true;
6026 
6027  // Handle manual resize: Resize Grips, Borders, Gamepad
6028  int border_held = -1;
6029  ImU32 resize_grip_col[4] = { 0 };
6030  const int resize_grip_count = (flags & ImGuiWindowFlags_ResizeFromAnySide) ? 2 : 1; // 4
6031  const float grip_draw_size = (float)(int)ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f);
6032  if (!window->Collapsed)
6033  UpdateManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0]);
6034 
6035  // Default item width. Make it proportional to window size if window manually resizes
6036  if (window->Size.x > 0.0f && !(flags & ImGuiWindowFlags_Tooltip) && !(flags & ImGuiWindowFlags_AlwaysAutoResize))
6037  window->ItemWidthDefault = (float)(int)(window->Size.x * 0.65f);
6038  else
6039  window->ItemWidthDefault = (float)(int)(g.FontSize * 16.0f);
6040 
6041  // DRAWING
6042 
6043  // Setup draw list and outer clipping rectangle
6044  window->DrawList->Clear();
6047  ImRect viewport_rect(GetViewportRect());
6048  if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip)
6049  PushClipRect(parent_window->ClipRect.Min, parent_window->ClipRect.Max, true);
6050  else
6051  PushClipRect(viewport_rect.Min, viewport_rect.Max, true);
6052 
6053  // Draw modal window background (darkens what is behind them)
6054  if ((flags & ImGuiWindowFlags_Modal) != 0 && window == GetFrontMostPopupModal())
6056 
6057  // Draw navigation selection/windowing rectangle background
6058  if (g.NavWindowingTarget == window)
6059  {
6060  ImRect bb = window->Rect();
6061  bb.Expand(g.FontSize);
6062  if (!bb.Contains(viewport_rect)) // Avoid drawing if the window covers all the viewport anyway
6064  }
6065 
6066  // Draw window + handle manual resize
6067  const float window_rounding = window->WindowRounding;
6068  const float window_border_size = window->WindowBorderSize;
6069  const bool title_bar_is_highlight = want_focus || (g.NavWindow && window->RootWindowForTitleBarHighlight == g.NavWindow->RootWindowForTitleBarHighlight);
6070  const ImRect title_bar_rect = window->TitleBarRect();
6071  if (window->Collapsed)
6072  {
6073  // Title bar only
6074  float backup_border_size = style.FrameBorderSize;
6076  ImU32 title_bar_col = GetColorU32((title_bar_is_highlight && !g.NavDisableHighlight) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBgCollapsed);
6077  RenderFrame(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, true, window_rounding);
6078  g.Style.FrameBorderSize = backup_border_size;
6079  }
6080  else
6081  {
6082  // Window background
6083  ImU32 bg_col = GetColorU32(GetWindowBgColorIdxFromFlags(flags));
6084  if (g.NextWindowData.BgAlphaCond != 0)
6085  {
6088  }
6089  window->DrawList->AddRectFilled(window->Pos+ImVec2(0,window->TitleBarHeight()), window->Pos+window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Bot);
6090 
6091  // Title bar
6092  ImU32 title_bar_col = GetColorU32(window->Collapsed ? ImGuiCol_TitleBgCollapsed : title_bar_is_highlight ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg);
6093  if (!(flags & ImGuiWindowFlags_NoTitleBar))
6094  window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, window_rounding, ImDrawCornerFlags_Top);
6095 
6096  // Menu bar
6097  if (flags & ImGuiWindowFlags_MenuBar)
6098  {
6099  ImRect menu_bar_rect = window->MenuBarRect();
6100  menu_bar_rect.ClipWith(window->Rect()); // Soft clipping, in particular child window don't have minimum size covering the menu bar so this is useful for them.
6101  window->DrawList->AddRectFilled(menu_bar_rect.Min, menu_bar_rect.Max, GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawCornerFlags_Top);
6102  if (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y)
6103  window->DrawList->AddLine(menu_bar_rect.GetBL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.FrameBorderSize);
6104  }
6105 
6106  // Scrollbars
6107  if (window->ScrollbarX)
6109  if (window->ScrollbarY)
6111 
6112  // Render resize grips (after their input handling so we don't have a frame of latency)
6113  if (!(flags & ImGuiWindowFlags_NoResize))
6114  {
6115  for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++)
6116  {
6117  const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n];
6118  const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPos);
6119  window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(window_border_size, grip_draw_size) : ImVec2(grip_draw_size, window_border_size)));
6120  window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(grip_draw_size, window_border_size) : ImVec2(window_border_size, grip_draw_size)));
6121  window->DrawList->PathArcToFast(ImVec2(corner.x + grip.InnerDir.x * (window_rounding + window_border_size), corner.y + grip.InnerDir.y * (window_rounding + window_border_size)), window_rounding, grip.AngleMin12, grip.AngleMax12);
6122  window->DrawList->PathFillConvex(resize_grip_col[resize_grip_n]);
6123  }
6124  }
6125 
6126  // Borders
6127  if (window_border_size > 0.0f)
6128  window->DrawList->AddRect(window->Pos, window->Pos + window->Size, GetColorU32(ImGuiCol_Border), window_rounding, ImDrawCornerFlags_All, window_border_size);
6129  if (border_held != -1)
6130  {
6131  ImRect border = GetBorderRect(window, border_held, grip_draw_size, 0.0f);
6132  window->DrawList->AddLine(border.Min, border.Max, GetColorU32(ImGuiCol_SeparatorActive), ImMax(1.0f, window_border_size));
6133  }
6134  if (style.FrameBorderSize > 0 && !(flags & ImGuiWindowFlags_NoTitleBar))
6135  window->DrawList->AddLine(title_bar_rect.GetBL() + ImVec2(style.WindowBorderSize, -1), title_bar_rect.GetBR() + ImVec2(-style.WindowBorderSize,-1), GetColorU32(ImGuiCol_Border), style.FrameBorderSize);
6136  }
6137 
6138  // Draw navigation selection/windowing rectangle border
6139  if (g.NavWindowingTarget == window)
6140  {
6141  float rounding = ImMax(window->WindowRounding, g.Style.WindowRounding);
6142  ImRect bb = window->Rect();
6143  bb.Expand(g.FontSize);
6144  if (bb.Contains(viewport_rect)) // If a window fits the entire viewport, adjust its highlight inward
6145  {
6146  bb.Expand(-g.FontSize - 1.0f);
6147  rounding = window->WindowRounding;
6148  }
6150  }
6151 
6152  // Store a backup of SizeFull which we will use next frame to decide if we need scrollbars.
6153  window->SizeFullAtLastBegin = window->SizeFull;
6154 
6155  // Update various regions. Variables they depends on are set above in this function.
6156  // FIXME: window->ContentsRegion.Max is currently very misleading / partly faulty, but some BeginChild() patterns relies on it.
6157  window->ContentsRegionRect.Min.x = window->Pos.x - window->Scroll.x + window->WindowPadding.x;
6158  window->ContentsRegionRect.Min.y = window->Pos.y - window->Scroll.y + window->WindowPadding.y + window->TitleBarHeight() + window->MenuBarHeight();
6159  window->ContentsRegionRect.Max.x = window->Pos.x - window->Scroll.x - window->WindowPadding.x + (window->SizeContentsExplicit.x != 0.0f ? window->SizeContentsExplicit.x : (window->Size.x - window->ScrollbarSizes.x));
6160  window->ContentsRegionRect.Max.y = window->Pos.y - window->Scroll.y - window->WindowPadding.y + (window->SizeContentsExplicit.y != 0.0f ? window->SizeContentsExplicit.y : (window->Size.y - window->ScrollbarSizes.y));
6161 
6162  // Setup drawing context
6163  // (NB: That term "drawing context / DC" lost its meaning a long time ago. Initially was meant to hold transient data only. Nowadays difference between window-> and window->DC-> is dubious.)
6164  window->DC.IndentX = 0.0f + window->WindowPadding.x - window->Scroll.x;
6165  window->DC.GroupOffsetX = 0.0f;
6166  window->DC.ColumnsOffsetX = 0.0f;
6167  window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.IndentX + window->DC.ColumnsOffsetX, window->TitleBarHeight() + window->MenuBarHeight() + window->WindowPadding.y - window->Scroll.y);
6168  window->DC.CursorPos = window->DC.CursorStartPos;
6169  window->DC.CursorPosPrevLine = window->DC.CursorPos;
6170  window->DC.CursorMaxPos = window->DC.CursorStartPos;
6171  window->DC.CurrentLineHeight = window->DC.PrevLineHeight = 0.0f;
6172  window->DC.CurrentLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f;
6173  window->DC.NavHideHighlightOneFrame = false;
6174  window->DC.NavHasScroll = (GetScrollMaxY() > 0.0f);
6175  window->DC.NavLayerActiveMask = window->DC.NavLayerActiveMaskNext;
6176  window->DC.NavLayerActiveMaskNext = 0x00;
6177  window->DC.MenuBarAppending = false;
6178  window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f;
6179  window->DC.ChildWindows.resize(0);
6181  window->DC.ParentLayoutType = parent_window ? parent_window->DC.LayoutType : ImGuiLayoutType_Vertical;
6183  window->DC.ItemWidth = window->ItemWidthDefault;
6184  window->DC.TextWrapPos = -1.0f; // disabled
6185  window->DC.ItemFlagsStack.resize(0);
6186  window->DC.ItemWidthStack.resize(0);
6187  window->DC.TextWrapPosStack.resize(0);
6188  window->DC.ColumnsSet = NULL;
6189  window->DC.TreeDepth = 0;
6190  window->DC.TreeDepthMayJumpToParentOnPop = 0x00;
6191  window->DC.StateStorage = &window->StateStorage;
6192  window->DC.GroupStack.resize(0);
6193  window->MenuColumns.Update(3, style.ItemSpacing.x, window_just_activated_by_user);
6194 
6195  if ((flags & ImGuiWindowFlags_ChildWindow) && (window->DC.ItemFlags != parent_window->DC.ItemFlags))
6196  {
6197  window->DC.ItemFlags = parent_window->DC.ItemFlags;
6198  window->DC.ItemFlagsStack.push_back(window->DC.ItemFlags);
6199  }
6200 
6201  if (window->AutoFitFramesX > 0)
6202  window->AutoFitFramesX--;
6203  if (window->AutoFitFramesY > 0)
6204  window->AutoFitFramesY--;
6205 
6206  // Apply focus (we need to call FocusWindow() AFTER setting DC.CursorStartPos so our initial navigation reference rectangle can start around there)
6207  if (want_focus)
6208  {
6209  FocusWindow(window);
6210  NavInitWindow(window, false);
6211  }
6212 
6213  // Title bar
6214  if (!(flags & ImGuiWindowFlags_NoTitleBar))
6215  {
6216  // Close & collapse button are on layer 1 (same as menus) and don't default focus
6217  const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags;
6219  window->DC.NavLayerCurrent++;
6220  window->DC.NavLayerCurrentMask <<= 1;
6221 
6222  // Collapse button
6223  if (!(flags & ImGuiWindowFlags_NoCollapse))
6224  {
6225  ImGuiID id = window->GetID("#COLLAPSE");
6226  ImRect bb(window->Pos + style.FramePadding + ImVec2(1,1), window->Pos + style.FramePadding + ImVec2(g.FontSize,g.FontSize) - ImVec2(1,1));
6227  ItemAdd(bb, id);
6228  if (ButtonBehavior(bb, id, NULL, NULL))
6229  window->CollapseToggleWanted = true; // Defer collapsing to next frame as we are too far in the Begin() function
6230  RenderNavHighlight(bb, id);
6231  RenderArrow(window->Pos + style.FramePadding, window->Collapsed ? ImGuiDir_Right : ImGuiDir_Down, 1.0f);
6232  }
6233 
6234  // Close button
6235  if (p_open != NULL)
6236  {
6237  const float pad = style.FramePadding.y;
6238  const float rad = g.FontSize * 0.5f;
6239  if (CloseButton(window->GetID("#CLOSE"), window->Rect().GetTR() + ImVec2(-pad - rad, pad + rad), rad + 1))
6240  *p_open = false;
6241  }
6242 
6243  window->DC.NavLayerCurrent--;
6244  window->DC.NavLayerCurrentMask >>= 1;
6245  window->DC.ItemFlags = item_flags_backup;
6246 
6247  // Title text (FIXME: refactor text alignment facilities along with RenderText helpers, this is too much code for what it does.)
6248  ImVec2 text_size = CalcTextSize(name, NULL, true);
6249  ImRect text_r = title_bar_rect;
6250  float pad_left = (flags & ImGuiWindowFlags_NoCollapse) ? style.FramePadding.x : (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x);
6251  float pad_right = (p_open == NULL) ? style.FramePadding.x : (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x);
6252  if (style.WindowTitleAlign.x > 0.0f)
6253  pad_right = ImLerp(pad_right, pad_left, style.WindowTitleAlign.x);
6254  text_r.Min.x += pad_left;
6255  text_r.Max.x -= pad_right;
6256  ImRect clip_rect = text_r;
6257  clip_rect.Max.x = window->Pos.x + window->Size.x - (p_open ? title_bar_rect.GetHeight() - 3 : style.FramePadding.x); // Match the size of CloseButton()
6258  RenderTextClipped(text_r.Min, text_r.Max, name, NULL, &text_size, style.WindowTitleAlign, &clip_rect);
6259  }
6260 
6261  // Save clipped aabb so we can access it in constant-time in FindHoveredWindow()
6262  window->OuterRectClipped = window->Rect();
6263  window->OuterRectClipped.ClipWith(window->ClipRect);
6264 
6265  // Pressing CTRL+C while holding on a window copy its content to the clipboard
6266  // This works but 1. doesn't handle multiple Begin/End pairs, 2. recursing into another Begin/End pair - so we need to work that out and add better logging scope.
6267  // Maybe we can support CTRL+C on every element?
6268  /*
6269  if (g.ActiveId == move_id)
6270  if (g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_C))
6271  ImGui::LogToClipboard();
6272  */
6273 
6274  // Inner rectangle
6275  // We set this up after processing the resize grip so that our clip rectangle doesn't lag by a frame
6276  // Note that if our window is collapsed we will end up with an inverted (~null) clipping rectangle which is the correct behavior.
6277  window->InnerMainRect.Min.x = title_bar_rect.Min.x + window->WindowBorderSize;
6278  window->InnerMainRect.Min.y = title_bar_rect.Max.y + window->MenuBarHeight() + (((flags & ImGuiWindowFlags_MenuBar) || !(flags & ImGuiWindowFlags_NoTitleBar)) ? style.FrameBorderSize : window->WindowBorderSize);
6279  window->InnerMainRect.Max.x = window->Pos.x + window->Size.x - window->ScrollbarSizes.x - window->WindowBorderSize;
6280  window->InnerMainRect.Max.y = window->Pos.y + window->Size.y - window->ScrollbarSizes.y - window->WindowBorderSize;
6281  //window->DrawList->AddRect(window->InnerRect.Min, window->InnerRect.Max, IM_COL32_WHITE);
6282 
6283  // Inner clipping rectangle
6284  // Force round operator last to ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result.
6285  window->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerMainRect.Min.x + ImMax(0.0f, ImFloor(window->WindowPadding.x*0.5f - window->WindowBorderSize)));
6286  window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerMainRect.Min.y);
6287  window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerMainRect.Max.x - ImMax(0.0f, ImFloor(window->WindowPadding.x*0.5f - window->WindowBorderSize)));
6288  window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerMainRect.Max.y);
6289 
6290  // After Begin() we fill the last item / hovered data based on title bar data. It is a standard behavior (to allow creation of context menus on title bar only, etc.).
6291  window->DC.LastItemId = window->MoveId;
6292  window->DC.LastItemStatusFlags = IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0;
6293  window->DC.LastItemRect = title_bar_rect;
6294  }
6295 
6296  PushClipRect(window->InnerClipRect.Min, window->InnerClipRect.Max, true);
6297 
6298  // Clear 'accessed' flag last thing (After PushClipRect which will set the flag. We want the flag to stay false when the default "Debug" window is unused)
6299  if (first_begin_of_the_frame)
6300  window->WriteAccessed = false;
6301 
6302  window->BeginCount++;
6303  g.NextWindowData.Clear();
6304 
6305  // Child window can be out of sight and have "negative" clip windows.
6306  // Mark them as collapsed so commands are skipped earlier (we can't manually collapse them because they have no title bar).
6307  if (flags & ImGuiWindowFlags_ChildWindow)
6308  {
6309  IM_ASSERT((flags & ImGuiWindowFlags_NoTitleBar) != 0);
6310  window->Collapsed = parent_window && parent_window->Collapsed;
6311 
6312  if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)
6313  window->Collapsed |= (window->OuterRectClipped.Min.x >= window->OuterRectClipped.Max.x || window->OuterRectClipped.Min.y >= window->OuterRectClipped.Max.y);
6314 
6315  // We also hide the window from rendering because we've already added its border to the command list.
6316  // (we could perform the check earlier in the function but it is simpler at this point)
6317  if (window->Collapsed)
6318  window->Active = false;
6319  }
6320  if (style.Alpha <= 0.0f)
6321  window->Active = false;
6322 
6323  // Return false if we don't intend to display anything to allow user to perform an early out optimization
6324  window->SkipItems = (window->Collapsed || !window->Active) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0;
6325  return !window->SkipItems;
6326 }
6327 
6328 // Old Begin() API with 5 parameters, avoid calling this version directly! Use SetNextWindowSize()/SetNextWindowBgAlpha() + Begin() instead.
6329 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
6330 bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_first_use, float bg_alpha_override, ImGuiWindowFlags flags)
6331 {
6332  // Old API feature: we could pass the initial window size as a parameter. This was misleading because it only had an effect if the window didn't have data in the .ini file.
6333  if (size_first_use.x != 0.0f || size_first_use.y != 0.0f)
6335 
6336  // Old API feature: override the window background alpha with a parameter.
6337  if (bg_alpha_override >= 0.0f)
6338  ImGui::SetNextWindowBgAlpha(bg_alpha_override);
6339 
6340  return ImGui::Begin(name, p_open, flags);
6341 }
6342 #endif // IMGUI_DISABLE_OBSOLETE_FUNCTIONS
6343 
6345 {
6346  ImGuiContext& g = *GImGui;
6347  ImGuiWindow* window = g.CurrentWindow;
6348 
6349  if (window->DC.ColumnsSet != NULL)
6350  EndColumns();
6351  PopClipRect(); // Inner window clip rectangle
6352 
6353  // Stop logging
6354  if (!(window->Flags & ImGuiWindowFlags_ChildWindow)) // FIXME: add more options for scope of logging
6355  LogFinish();
6356 
6357  // Pop from window stack
6359  if (window->Flags & ImGuiWindowFlags_Popup)
6361  CheckStacksSize(window, false);
6362  SetCurrentWindow(g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back());
6363 }
6364 
6365 // Vertical scrollbar
6366 // The entire piece of code below is rather confusing because:
6367 // - We handle absolute seeking (when first clicking outside the grab) and relative manipulation (afterward or when clicking inside the grab)
6368 // - We store values as normalized ratio and in a form that allows the window content to change while we are holding on a scrollbar
6369 // - We handle both horizontal and vertical scrollbars, which makes the terminology not ideal.
6371 {
6372  ImGuiContext& g = *GImGui;
6373  ImGuiWindow* window = g.CurrentWindow;
6374 
6375  const bool horizontal = (direction == ImGuiLayoutType_Horizontal);
6376  const ImGuiStyle& style = g.Style;
6377  const ImGuiID id = window->GetID(horizontal ? "#SCROLLX" : "#SCROLLY");
6378 
6379  // Render background
6380  bool other_scrollbar = (horizontal ? window->ScrollbarY : window->ScrollbarX);
6381  float other_scrollbar_size_w = other_scrollbar ? style.ScrollbarSize : 0.0f;
6382  const ImRect window_rect = window->Rect();
6383  const float border_size = window->WindowBorderSize;
6384  ImRect bb = horizontal
6385  ? ImRect(window->Pos.x + border_size, window_rect.Max.y - style.ScrollbarSize, window_rect.Max.x - other_scrollbar_size_w - border_size, window_rect.Max.y - border_size)
6386  : ImRect(window_rect.Max.x - style.ScrollbarSize, window->Pos.y + border_size, window_rect.Max.x - border_size, window_rect.Max.y - other_scrollbar_size_w - border_size);
6387  if (!horizontal)
6388  bb.Min.y += window->TitleBarHeight() + ((window->Flags & ImGuiWindowFlags_MenuBar) ? window->MenuBarHeight() : 0.0f);
6389  if (bb.GetWidth() <= 0.0f || bb.GetHeight() <= 0.0f)
6390  return;
6391 
6392  int window_rounding_corners;
6393  if (horizontal)
6394  window_rounding_corners = ImDrawCornerFlags_BotLeft | (other_scrollbar ? 0 : ImDrawCornerFlags_BotRight);
6395  else
6396  window_rounding_corners = (((window->Flags & ImGuiWindowFlags_NoTitleBar) && !(window->Flags & ImGuiWindowFlags_MenuBar)) ? ImDrawCornerFlags_TopRight : 0) | (other_scrollbar ? 0 : ImDrawCornerFlags_BotRight);
6397  window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_ScrollbarBg), window->WindowRounding, window_rounding_corners);
6398  bb.Expand(ImVec2(-ImClamp((float)(int)((bb.Max.x - bb.Min.x - 2.0f) * 0.5f), 0.0f, 3.0f), -ImClamp((float)(int)((bb.Max.y - bb.Min.y - 2.0f) * 0.5f), 0.0f, 3.0f)));
6399 
6400  // V denote the main, longer axis of the scrollbar (= height for a vertical scrollbar)
6401  float scrollbar_size_v = horizontal ? bb.GetWidth() : bb.GetHeight();
6402  float scroll_v = horizontal ? window->Scroll.x : window->Scroll.y;
6403  float win_size_avail_v = (horizontal ? window->SizeFull.x : window->SizeFull.y) - other_scrollbar_size_w;
6404  float win_size_contents_v = horizontal ? window->SizeContents.x : window->SizeContents.y;
6405 
6406  // Calculate the height of our grabbable box. It generally represent the amount visible (vs the total scrollable amount)
6407  // But we maintain a minimum size in pixel to allow for the user to still aim inside.
6408  IM_ASSERT(ImMax(win_size_contents_v, win_size_avail_v) > 0.0f); // Adding this assert to check if the ImMax(XXX,1.0f) is still needed. PLEASE CONTACT ME if this triggers.
6409  const float win_size_v = ImMax(ImMax(win_size_contents_v, win_size_avail_v), 1.0f);
6410  const float grab_h_pixels = ImClamp(scrollbar_size_v * (win_size_avail_v / win_size_v), style.GrabMinSize, scrollbar_size_v);
6411  const float grab_h_norm = grab_h_pixels / scrollbar_size_v;
6412 
6413  // Handle input right away. None of the code of Begin() is relying on scrolling position before calling Scrollbar().
6414  bool held = false;
6415  bool hovered = false;
6416  const bool previously_held = (g.ActiveId == id);
6417  ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_NoNavFocus);
6418 
6419  float scroll_max = ImMax(1.0f, win_size_contents_v - win_size_avail_v);
6420  float scroll_ratio = ImSaturate(scroll_v / scroll_max);
6421  float grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v;
6422  if (held && grab_h_norm < 1.0f)
6423  {
6424  float scrollbar_pos_v = horizontal ? bb.Min.x : bb.Min.y;
6425  float mouse_pos_v = horizontal ? g.IO.MousePos.x : g.IO.MousePos.y;
6426  float* click_delta_to_grab_center_v = horizontal ? &g.ScrollbarClickDeltaToGrabCenter.x : &g.ScrollbarClickDeltaToGrabCenter.y;
6427 
6428  // Click position in scrollbar normalized space (0.0f->1.0f)
6429  const float clicked_v_norm = ImSaturate((mouse_pos_v - scrollbar_pos_v) / scrollbar_size_v);
6430  SetHoveredID(id);
6431 
6432  bool seek_absolute = false;
6433  if (!previously_held)
6434  {
6435  // On initial click calculate the distance between mouse and the center of the grab
6436  if (clicked_v_norm >= grab_v_norm && clicked_v_norm <= grab_v_norm + grab_h_norm)
6437  {
6438  *click_delta_to_grab_center_v = clicked_v_norm - grab_v_norm - grab_h_norm*0.5f;
6439  }
6440  else
6441  {
6442  seek_absolute = true;
6443  *click_delta_to_grab_center_v = 0.0f;
6444  }
6445  }
6446 
6447  // Apply scroll
6448  // It is ok to modify Scroll here because we are being called in Begin() after the calculation of SizeContents and before setting up our starting position
6449  const float scroll_v_norm = ImSaturate((clicked_v_norm - *click_delta_to_grab_center_v - grab_h_norm*0.5f) / (1.0f - grab_h_norm));
6450  scroll_v = (float)(int)(0.5f + scroll_v_norm * scroll_max);//(win_size_contents_v - win_size_v));
6451  if (horizontal)
6452  window->Scroll.x = scroll_v;
6453  else
6454  window->Scroll.y = scroll_v;
6455 
6456  // Update values for rendering
6457  scroll_ratio = ImSaturate(scroll_v / scroll_max);
6458  grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v;
6459 
6460  // Update distance to grab now that we have seeked and saturated
6461  if (seek_absolute)
6462  *click_delta_to_grab_center_v = clicked_v_norm - grab_v_norm - grab_h_norm*0.5f;
6463  }
6464 
6465  // Render
6467  ImRect grab_rect;
6468  if (horizontal)
6469  grab_rect = ImRect(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm), bb.Min.y, ImMin(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm) + grab_h_pixels, window_rect.Max.x), bb.Max.y);
6470  else
6471  grab_rect = ImRect(bb.Min.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm), bb.Max.x, ImMin(ImLerp(bb.Min.y, bb.Max.y, grab_v_norm) + grab_h_pixels, window_rect.Max.y));
6472  window->DrawList->AddRectFilled(grab_rect.Min, grab_rect.Max, grab_col, style.ScrollbarRounding);
6473 }
6474 
6476 {
6477  ImGuiContext& g = *GImGui;
6478  ImGuiWindow* current_front_window = g.Windows.back();
6479  if (current_front_window == window || current_front_window->RootWindow == window)
6480  return;
6481  for (int i = g.Windows.Size - 2; i >= 0; i--) // We can ignore the front most window
6482  if (g.Windows[i] == window)
6483  {
6484  g.Windows.erase(g.Windows.Data + i);
6485  g.Windows.push_back(window);
6486  break;
6487  }
6488 }
6489 
6491 {
6492  ImGuiContext& g = *GImGui;
6493  if (g.Windows[0] == window)
6494  return;
6495  for (int i = 0; i < g.Windows.Size; i++)
6496  if (g.Windows[i] == window)
6497  {
6498  memmove(&g.Windows[1], &g.Windows[0], (size_t)i * sizeof(ImGuiWindow*));
6499  g.Windows[0] = window;
6500  break;
6501  }
6502 }
6503 
6504 // Moving window to front of display and set focus (which happens to be back of our sorted list)
6506 {
6507  ImGuiContext& g = *GImGui;
6508 
6509  if (g.NavWindow != window)
6510  {
6511  g.NavWindow = window;
6512  if (window && g.NavDisableMouseHover)
6513  g.NavMousePosDirty = true;
6514  g.NavInitRequest = false;
6515  g.NavId = window ? window->NavLastIds[0] : 0; // Restore NavId
6516  g.NavIdIsAlive = false;
6517  g.NavLayer = 0;
6518  //printf("[%05d] FocusWindow(\"%s\")\n", g.FrameCount, window ? window->Name : NULL);
6519  }
6520 
6521  // Passing NULL allow to disable keyboard focus
6522  if (!window)
6523  return;
6524 
6525  // Move the root window to the top of the pile
6526  if (window->RootWindow)
6527  window = window->RootWindow;
6528 
6529  // Steal focus on active widgets
6530  if (window->Flags & ImGuiWindowFlags_Popup) // FIXME: This statement should be unnecessary. Need further testing before removing it..
6531  if (g.ActiveId != 0 && g.ActiveIdWindow && g.ActiveIdWindow->RootWindow != window)
6532  ClearActiveID();
6533 
6534  // Bring to front
6535  if (!(window->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus))
6536  BringWindowToFront(window);
6537 }
6538 
6539 void ImGui::FocusFrontMostActiveWindow(ImGuiWindow* ignore_window)
6540 {
6541  ImGuiContext& g = *GImGui;
6542  for (int i = g.Windows.Size - 1; i >= 0; i--)
6543  if (g.Windows[i] != ignore_window && g.Windows[i]->WasActive && !(g.Windows[i]->Flags & ImGuiWindowFlags_ChildWindow))
6544  {
6545  ImGuiWindow* focus_window = NavRestoreLastChildNavWindow(g.Windows[i]);
6546  FocusWindow(focus_window);
6547  return;
6548  }
6549 }
6550 
6551 void ImGui::PushItemWidth(float item_width)
6552 {
6553  ImGuiWindow* window = GetCurrentWindow();
6554  window->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width);
6555  window->DC.ItemWidthStack.push_back(window->DC.ItemWidth);
6556 }
6557 
6559 {
6560  ImGuiWindow* window = GetCurrentWindow();
6561  const ImGuiStyle& style = GImGui->Style;
6562  if (w_full <= 0.0f)
6563  w_full = CalcItemWidth();
6564  const float w_item_one = ImMax(1.0f, (float)(int)((w_full - (style.ItemInnerSpacing.x) * (components-1)) / (float)components));
6565  const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one + style.ItemInnerSpacing.x) * (components-1)));
6566  window->DC.ItemWidthStack.push_back(w_item_last);
6567  for (int i = 0; i < components-1; i++)
6568  window->DC.ItemWidthStack.push_back(w_item_one);
6569  window->DC.ItemWidth = window->DC.ItemWidthStack.back();
6570 }
6571 
6573 {
6574  ImGuiWindow* window = GetCurrentWindow();
6575  window->DC.ItemWidthStack.pop_back();
6576  window->DC.ItemWidth = window->DC.ItemWidthStack.empty() ? window->ItemWidthDefault : window->DC.ItemWidthStack.back();
6577 }
6578 
6580 {
6581  ImGuiWindow* window = GetCurrentWindowRead();
6582  float w = window->DC.ItemWidth;
6583  if (w < 0.0f)
6584  {
6585  // Align to a right-side limit. We include 1 frame padding in the calculation because this is how the width is always used (we add 2 frame padding to it), but we could move that responsibility to the widget as well.
6586  float width_to_right_edge = GetContentRegionAvail().x;
6587  w = ImMax(1.0f, width_to_right_edge + w);
6588  }
6589  w = (float)(int)w;
6590  return w;
6591 }
6592 
6593 static ImFont* GetDefaultFont()
6594 {
6595  ImGuiContext& g = *GImGui;
6596  return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0];
6597 }
6598 
6600 {
6601  ImGuiContext& g = *GImGui;
6602  IM_ASSERT(font && font->IsLoaded()); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ?
6603  IM_ASSERT(font->Scale > 0.0f);
6604  g.Font = font;
6606  g.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f;
6607 
6608  ImFontAtlas* atlas = g.Font->ContainerAtlas;
6612 }
6613 
6615 {
6616  ImGuiContext& g = *GImGui;
6617  if (!font)
6618  font = GetDefaultFont();
6619  SetCurrentFont(font);
6620  g.FontStack.push_back(font);
6622 }
6623 
6625 {
6626  ImGuiContext& g = *GImGui;
6628  g.FontStack.pop_back();
6629  SetCurrentFont(g.FontStack.empty() ? GetDefaultFont() : g.FontStack.back());
6630 }
6631 
6633 {
6634  ImGuiWindow* window = GetCurrentWindow();
6635  if (enabled)
6636  window->DC.ItemFlags |= option;
6637  else
6638  window->DC.ItemFlags &= ~option;
6639  window->DC.ItemFlagsStack.push_back(window->DC.ItemFlags);
6640 }
6641 
6643 {
6644  ImGuiWindow* window = GetCurrentWindow();
6645  window->DC.ItemFlagsStack.pop_back();
6646  window->DC.ItemFlags = window->DC.ItemFlagsStack.empty() ? ImGuiItemFlags_Default_ : window->DC.ItemFlagsStack.back();
6647 }
6648 
6649 void ImGui::PushAllowKeyboardFocus(bool allow_keyboard_focus)
6650 {
6651  PushItemFlag(ImGuiItemFlags_AllowKeyboardFocus, allow_keyboard_focus);
6652 }
6653 
6655 {
6656  PopItemFlag();
6657 }
6658 
6659 void ImGui::PushButtonRepeat(bool repeat)
6660 {
6662 }
6663 
6665 {
6666  PopItemFlag();
6667 }
6668 
6669 void ImGui::PushTextWrapPos(float wrap_pos_x)
6670 {
6671  ImGuiWindow* window = GetCurrentWindow();
6672  window->DC.TextWrapPos = wrap_pos_x;
6673  window->DC.TextWrapPosStack.push_back(wrap_pos_x);
6674 }
6675 
6677 {
6678  ImGuiWindow* window = GetCurrentWindow();
6679  window->DC.TextWrapPosStack.pop_back();
6680  window->DC.TextWrapPos = window->DC.TextWrapPosStack.empty() ? -1.0f : window->DC.TextWrapPosStack.back();
6681 }
6682 
6683 // FIXME: This may incur a round-trip (if the end user got their data from a float4) but eventually we aim to store the in-flight colors as ImU32
6685 {
6686  ImGuiContext& g = *GImGui;
6687  ImGuiColMod backup;
6688  backup.Col = idx;
6689  backup.BackupValue = g.Style.Colors[idx];
6690  g.ColorModifiers.push_back(backup);
6691  g.Style.Colors[idx] = ColorConvertU32ToFloat4(col);
6692 }
6693 
6695 {
6696  ImGuiContext& g = *GImGui;
6697  ImGuiColMod backup;
6698  backup.Col = idx;
6699  backup.BackupValue = g.Style.Colors[idx];
6700  g.ColorModifiers.push_back(backup);
6701  g.Style.Colors[idx] = col;
6702 }
6703 
6704 void ImGui::PopStyleColor(int count)
6705 {
6706  ImGuiContext& g = *GImGui;
6707  while (count > 0)
6708  {
6709  ImGuiColMod& backup = g.ColorModifiers.back();
6710  g.Style.Colors[backup.Col] = backup.BackupValue;
6712  count--;
6713  }
6714 }
6715 
6717 {
6721  void* GetVarPtr(ImGuiStyle* style) const { return (void*)((unsigned char*)style + Offset); }
6722 };
6723 
6724 static const ImGuiStyleVarInfo GStyleVarInfo[] =
6725 {
6726  { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, Alpha) }, // ImGuiStyleVar_Alpha
6727  { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowPadding) }, // ImGuiStyleVar_WindowPadding
6728  { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowRounding) }, // ImGuiStyleVar_WindowRounding
6729  { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowBorderSize) }, // ImGuiStyleVar_WindowBorderSize
6730  { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowMinSize) }, // ImGuiStyleVar_WindowMinSize
6731  { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowTitleAlign) }, // ImGuiStyleVar_WindowTitleAlign
6732  { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildRounding) }, // ImGuiStyleVar_ChildRounding
6733  { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildBorderSize) }, // ImGuiStyleVar_ChildBorderSize
6734  { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupRounding) }, // ImGuiStyleVar_PopupRounding
6735  { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupBorderSize) }, // ImGuiStyleVar_PopupBorderSize
6736  { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, FramePadding) }, // ImGuiStyleVar_FramePadding
6737  { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameRounding) }, // ImGuiStyleVar_FrameRounding
6738  { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameBorderSize) }, // ImGuiStyleVar_FrameBorderSize
6739  { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemSpacing) }, // ImGuiStyleVar_ItemSpacing
6740  { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemInnerSpacing) }, // ImGuiStyleVar_ItemInnerSpacing
6741  { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, IndentSpacing) }, // ImGuiStyleVar_IndentSpacing
6742  { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarSize) }, // ImGuiStyleVar_ScrollbarSize
6743  { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarRounding) }, // ImGuiStyleVar_ScrollbarRounding
6744  { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabMinSize) }, // ImGuiStyleVar_GrabMinSize
6745  { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabRounding) }, // ImGuiStyleVar_GrabRounding
6746  { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign
6747 };
6748 
6749 static const ImGuiStyleVarInfo* GetStyleVarInfo(ImGuiStyleVar idx)
6750 {
6751  IM_ASSERT(idx >= 0 && idx < ImGuiStyleVar_COUNT);
6752  IM_ASSERT(IM_ARRAYSIZE(GStyleVarInfo) == ImGuiStyleVar_COUNT);
6753  return &GStyleVarInfo[idx];
6754 }
6755 
6757 {
6758  const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx);
6759  if (var_info->Type == ImGuiDataType_Float && var_info->Count == 1)
6760  {
6761  ImGuiContext& g = *GImGui;
6762  float* pvar = (float*)var_info->GetVarPtr(&g.Style);
6763  g.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar));
6764  *pvar = val;
6765  return;
6766  }
6767  IM_ASSERT(0); // Called function with wrong-type? Variable is not a float.
6768 }
6769 
6771 {
6772  const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx);
6773  if (var_info->Type == ImGuiDataType_Float && var_info->Count == 2)
6774  {
6775  ImGuiContext& g = *GImGui;
6776  ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style);
6777  g.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar));
6778  *pvar = val;
6779  return;
6780  }
6781  IM_ASSERT(0); // Called function with wrong-type? Variable is not a ImVec2.
6782 }
6783 
6784 void ImGui::PopStyleVar(int count)
6785 {
6786  ImGuiContext& g = *GImGui;
6787  while (count > 0)
6788  {
6789  // We avoid a generic memcpy(data, &backup.Backup.., GDataTypeSize[info->Type] * info->Count), the overhead in Debug is not worth it.
6790  ImGuiStyleMod& backup = g.StyleModifiers.back();
6791  const ImGuiStyleVarInfo* info = GetStyleVarInfo(backup.VarIdx);
6792  void* data = info->GetVarPtr(&g.Style);
6793  if (info->Type == ImGuiDataType_Float && info->Count == 1) { ((float*)data)[0] = backup.BackupFloat[0]; }
6794  else if (info->Type == ImGuiDataType_Float && info->Count == 2) { ((float*)data)[0] = backup.BackupFloat[0]; ((float*)data)[1] = backup.BackupFloat[1]; }
6796  count--;
6797  }
6798 }
6799 
6801 {
6802  // Create switch-case from enum with regexp: ImGuiCol_{.*}, --> case ImGuiCol_\1: return "\1";
6803  switch (idx)
6804  {
6805  case ImGuiCol_Text: return "Text";
6806  case ImGuiCol_TextDisabled: return "TextDisabled";
6807  case ImGuiCol_WindowBg: return "WindowBg";
6808  case ImGuiCol_ChildBg: return "ChildBg";
6809  case ImGuiCol_PopupBg: return "PopupBg";
6810  case ImGuiCol_Border: return "Border";
6811  case ImGuiCol_BorderShadow: return "BorderShadow";
6812  case ImGuiCol_FrameBg: return "FrameBg";
6813  case ImGuiCol_FrameBgHovered: return "FrameBgHovered";
6814  case ImGuiCol_FrameBgActive: return "FrameBgActive";
6815  case ImGuiCol_TitleBg: return "TitleBg";
6816  case ImGuiCol_TitleBgActive: return "TitleBgActive";
6817  case ImGuiCol_TitleBgCollapsed: return "TitleBgCollapsed";
6818  case ImGuiCol_MenuBarBg: return "MenuBarBg";
6819  case ImGuiCol_ScrollbarBg: return "ScrollbarBg";
6820  case ImGuiCol_ScrollbarGrab: return "ScrollbarGrab";
6821  case ImGuiCol_ScrollbarGrabHovered: return "ScrollbarGrabHovered";
6822  case ImGuiCol_ScrollbarGrabActive: return "ScrollbarGrabActive";
6823  case ImGuiCol_CheckMark: return "CheckMark";
6824  case ImGuiCol_SliderGrab: return "SliderGrab";
6825  case ImGuiCol_SliderGrabActive: return "SliderGrabActive";
6826  case ImGuiCol_Button: return "Button";
6827  case ImGuiCol_ButtonHovered: return "ButtonHovered";
6828  case ImGuiCol_ButtonActive: return "ButtonActive";
6829  case ImGuiCol_Header: return "Header";
6830  case ImGuiCol_HeaderHovered: return "HeaderHovered";
6831  case ImGuiCol_HeaderActive: return "HeaderActive";
6832  case ImGuiCol_Separator: return "Separator";
6833  case ImGuiCol_SeparatorHovered: return "SeparatorHovered";
6834  case ImGuiCol_SeparatorActive: return "SeparatorActive";
6835  case ImGuiCol_ResizeGrip: return "ResizeGrip";
6836  case ImGuiCol_ResizeGripHovered: return "ResizeGripHovered";
6837  case ImGuiCol_ResizeGripActive: return "ResizeGripActive";
6838  case ImGuiCol_PlotLines: return "PlotLines";
6839  case ImGuiCol_PlotLinesHovered: return "PlotLinesHovered";
6840  case ImGuiCol_PlotHistogram: return "PlotHistogram";
6841  case ImGuiCol_PlotHistogramHovered: return "PlotHistogramHovered";
6842  case ImGuiCol_TextSelectedBg: return "TextSelectedBg";
6843  case ImGuiCol_ModalWindowDarkening: return "ModalWindowDarkening";
6844  case ImGuiCol_DragDropTarget: return "DragDropTarget";
6845  case ImGuiCol_NavHighlight: return "NavHighlight";
6846  case ImGuiCol_NavWindowingHighlight: return "NavWindowingHighlight";
6847  }
6848  IM_ASSERT(0);
6849  return "Unknown";
6850 }
6851 
6852 bool ImGui::IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent)
6853 {
6854  if (window->RootWindow == potential_parent)
6855  return true;
6856  while (window != NULL)
6857  {
6858  if (window == potential_parent)
6859  return true;
6860  window = window->ParentWindow;
6861  }
6862  return false;
6863 }
6864 
6866 {
6867  IM_ASSERT((flags & ImGuiHoveredFlags_AllowWhenOverlapped) == 0); // Flags not supported by this function
6868  ImGuiContext& g = *GImGui;
6869 
6870  if (flags & ImGuiHoveredFlags_AnyWindow)
6871  {
6872  if (g.HoveredWindow == NULL)
6873  return false;
6874  }
6875  else
6876  {
6878  {
6881  return false;
6882  break;
6885  return false;
6886  break;
6888  if (g.HoveredWindow == NULL || !IsWindowChildOf(g.HoveredWindow, g.CurrentWindow))
6889  return false;
6890  break;
6891  default:
6892  if (g.HoveredWindow != g.CurrentWindow)
6893  return false;
6894  break;
6895  }
6896  }
6897 
6898  if (!IsWindowContentHoverable(g.HoveredRootWindow, flags))
6899  return false;
6901  if (g.ActiveId != 0 && !g.ActiveIdAllowOverlap && g.ActiveId != g.HoveredWindow->MoveId)
6902  return false;
6903  return true;
6904 }
6905 
6907 {
6908  ImGuiContext& g = *GImGui;
6909  IM_ASSERT(g.CurrentWindow); // Not inside a Begin()/End()
6910 
6911  if (flags & ImGuiFocusedFlags_AnyWindow)
6912  return g.NavWindow != NULL;
6913 
6915  {
6917  return g.NavWindow && g.NavWindow->RootWindow == g.CurrentWindow->RootWindow;
6919  return g.NavWindow == g.CurrentWindow->RootWindow;
6922  default:
6923  return g.NavWindow == g.CurrentWindow;
6924  }
6925 }
6926 
6927 // Can we focus this window with CTRL+TAB (or PadMenu + PadFocusPrev/PadFocusNext)
6929 {
6930  ImGuiContext& g = *GImGui;
6931  return window->Active && window == window->RootWindowForTabbing && (!(window->Flags & ImGuiWindowFlags_NoNavFocus) || window == g.NavWindow);
6932 }
6933 
6935 {
6936  ImGuiWindow* window = GImGui->CurrentWindow;
6937  return window->Size.x;
6938 }
6939 
6941 {
6942  ImGuiWindow* window = GImGui->CurrentWindow;
6943  return window->Size.y;
6944 }
6945 
6947 {
6948  ImGuiContext& g = *GImGui;
6949  ImGuiWindow* window = g.CurrentWindow;
6950  return window->Pos;
6951 }
6952 
6953 static void SetWindowScrollX(ImGuiWindow* window, float new_scroll_x)
6954 {
6955  window->DC.CursorMaxPos.x += window->Scroll.x; // SizeContents is generally computed based on CursorMaxPos which is affected by scroll position, so we need to apply our change to it.
6956  window->Scroll.x = new_scroll_x;
6957  window->DC.CursorMaxPos.x -= window->Scroll.x;
6958 }
6959 
6960 static void SetWindowScrollY(ImGuiWindow* window, float new_scroll_y)
6961 {
6962  window->DC.CursorMaxPos.y += window->Scroll.y; // SizeContents is generally computed based on CursorMaxPos which is affected by scroll position, so we need to apply our change to it.
6963  window->Scroll.y = new_scroll_y;
6964  window->DC.CursorMaxPos.y -= window->Scroll.y;
6965 }
6966 
6967 static void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond)
6968 {
6969  // Test condition (NB: bit 0 is always true) and clear flags for next time
6970  if (cond && (window->SetWindowPosAllowFlags & cond) == 0)
6971  return;
6972 
6973  IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
6975  window->SetWindowPosVal = ImVec2(FLT_MAX, FLT_MAX);
6976 
6977  // Set
6978  const ImVec2 old_pos = window->Pos;
6979  window->Pos = ImFloor(pos);
6980  window->DC.CursorPos += (window->Pos - old_pos); // As we happen to move the window while it is being appended to (which is a bad idea - will smear) let's at least offset the cursor
6981  window->DC.CursorMaxPos += (window->Pos - old_pos); // And more importantly we need to adjust this so size calculation doesn't get affected.
6982 }
6983 
6984 void ImGui::SetWindowPos(const ImVec2& pos, ImGuiCond cond)
6985 {
6986  ImGuiWindow* window = GetCurrentWindowRead();
6987  SetWindowPos(window, pos, cond);
6988 }
6989 
6990 void ImGui::SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond)
6991 {
6992  if (ImGuiWindow* window = FindWindowByName(name))
6993  SetWindowPos(window, pos, cond);
6994 }
6995 
6997 {
6998  ImGuiWindow* window = GetCurrentWindowRead();
6999  return window->Size;
7000 }
7001 
7002 static void SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond)
7003 {
7004  // Test condition (NB: bit 0 is always true) and clear flags for next time
7005  if (cond && (window->SetWindowSizeAllowFlags & cond) == 0)
7006  return;
7007 
7008  IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
7010 
7011  // Set
7012  if (size.x > 0.0f)
7013  {
7014  window->AutoFitFramesX = 0;
7015  window->SizeFull.x = size.x;
7016  }
7017  else
7018  {
7019  window->AutoFitFramesX = 2;
7020  window->AutoFitOnlyGrows = false;
7021  }
7022  if (size.y > 0.0f)
7023  {
7024  window->AutoFitFramesY = 0;
7025  window->SizeFull.y = size.y;
7026  }
7027  else
7028  {
7029  window->AutoFitFramesY = 2;
7030  window->AutoFitOnlyGrows = false;
7031  }
7032 }
7033 
7034 void ImGui::SetWindowSize(const ImVec2& size, ImGuiCond cond)
7035 {
7036  SetWindowSize(GImGui->CurrentWindow, size, cond);
7037 }
7038 
7039 void ImGui::SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond)
7040 {
7041  if (ImGuiWindow* window = FindWindowByName(name))
7042  SetWindowSize(window, size, cond);
7043 }
7044 
7045 static void SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond)
7046 {
7047  // Test condition (NB: bit 0 is always true) and clear flags for next time
7048  if (cond && (window->SetWindowCollapsedAllowFlags & cond) == 0)
7049  return;
7051 
7052  // Set
7053  window->Collapsed = collapsed;
7054 }
7055 
7056 void ImGui::SetWindowCollapsed(bool collapsed, ImGuiCond cond)
7057 {
7058  SetWindowCollapsed(GImGui->CurrentWindow, collapsed, cond);
7059 }
7060 
7062 {
7063  ImGuiWindow* window = GetCurrentWindowRead();
7064  return window->Collapsed;
7065 }
7066 
7068 {
7069  ImGuiWindow* window = GetCurrentWindowRead();
7070  return window->Appearing;
7071 }
7072 
7073 void ImGui::SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond)
7074 {
7075  if (ImGuiWindow* window = FindWindowByName(name))
7076  SetWindowCollapsed(window, collapsed, cond);
7077 }
7078 
7080 {
7081  FocusWindow(GImGui->CurrentWindow);
7082 }
7083 
7084 void ImGui::SetWindowFocus(const char* name)
7085 {
7086  if (name)
7087  {
7088  if (ImGuiWindow* window = FindWindowByName(name))
7089  FocusWindow(window);
7090  }
7091  else
7092  {
7093  FocusWindow(NULL);
7094  }
7095 }
7096 
7097 void ImGui::SetNextWindowPos(const ImVec2& pos, ImGuiCond cond, const ImVec2& pivot)
7098 {
7099  ImGuiContext& g = *GImGui;
7100  IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
7101  g.NextWindowData.PosVal = pos;
7102  g.NextWindowData.PosPivotVal = pivot;
7103  g.NextWindowData.PosCond = cond ? cond : ImGuiCond_Always;
7104 }
7105 
7107 {
7108  ImGuiContext& g = *GImGui;
7109  IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
7111  g.NextWindowData.SizeCond = cond ? cond : ImGuiCond_Always;
7112 }
7113 
7114 void ImGui::SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback, void* custom_callback_user_data)
7115 {
7116  ImGuiContext& g = *GImGui;
7118  g.NextWindowData.SizeConstraintRect = ImRect(size_min, size_max);
7119  g.NextWindowData.SizeCallback = custom_callback;
7120  g.NextWindowData.SizeCallbackUserData = custom_callback_user_data;
7121 }
7122 
7124 {
7125  ImGuiContext& g = *GImGui;
7126  g.NextWindowData.ContentSizeVal = size; // In Begin() we will add the size of window decorations (title bar, menu etc.) to that to form a SizeContents value.
7128 }
7129 
7130 void ImGui::SetNextWindowCollapsed(bool collapsed, ImGuiCond cond)
7131 {
7132  ImGuiContext& g = *GImGui;
7133  IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
7134  g.NextWindowData.CollapsedVal = collapsed;
7135  g.NextWindowData.CollapsedCond = cond ? cond : ImGuiCond_Always;
7136 }
7137 
7139 {
7140  ImGuiContext& g = *GImGui;
7141  g.NextWindowData.FocusCond = ImGuiCond_Always; // Using a Cond member for consistency (may transition all of them to single flag set for fast Clear() op)
7142 }
7143 
7145 {
7146  ImGuiContext& g = *GImGui;
7148  g.NextWindowData.BgAlphaCond = ImGuiCond_Always; // Using a Cond member for consistency (may transition all of them to single flag set for fast Clear() op)
7149 }
7150 
7151 // In window space (not screen space!)
7153 {
7154  ImGuiWindow* window = GetCurrentWindowRead();
7155  ImVec2 mx = window->ContentsRegionRect.Max - window->Pos;
7156  if (window->DC.ColumnsSet)
7157  mx.x = GetColumnOffset(window->DC.ColumnsSet->Current + 1) - window->WindowPadding.x;
7158  return mx;
7159 }
7160 
7162 {
7163  ImGuiWindow* window = GetCurrentWindowRead();
7164  return GetContentRegionMax() - (window->DC.CursorPos - window->Pos);
7165 }
7166 
7168 {
7169  return GetContentRegionAvail().x;
7170 }
7171 
7172 // In window space (not screen space!)
7174 {
7175  ImGuiWindow* window = GetCurrentWindowRead();
7176  return window->ContentsRegionRect.Min - window->Pos;
7177 }
7178 
7180 {
7181  ImGuiWindow* window = GetCurrentWindowRead();
7182  return window->ContentsRegionRect.Max - window->Pos;
7183 }
7184 
7186 {
7187  ImGuiWindow* window = GetCurrentWindowRead();
7188  return window->ContentsRegionRect.GetWidth();
7189 }
7190 
7192 {
7193  ImGuiContext& g = *GImGui;
7194  return g.FontSize;
7195 }
7196 
7198 {
7199  ImGuiContext& g = *GImGui;
7200  return g.FontSize + g.Style.ItemSpacing.y;
7201 }
7202 
7204 {
7205  ImGuiContext& g = *GImGui;
7206  return g.FontSize + g.Style.FramePadding.y * 2.0f;
7207 }
7208 
7210 {
7211  ImGuiContext& g = *GImGui;
7212  return g.FontSize + g.Style.FramePadding.y * 2.0f + g.Style.ItemSpacing.y;
7213 }
7214 
7216 {
7217  ImGuiWindow* window = GetCurrentWindow();
7218  return window->DrawList;
7219 }
7220 
7222 {
7223  return GImGui->Font;
7224 }
7225 
7227 {
7228  return GImGui->FontSize;
7229 }
7230 
7232 {
7233  return GImGui->DrawListSharedData.TexUvWhitePixel;
7234 }
7235 
7236 void ImGui::SetWindowFontScale(float scale)
7237 {
7238  ImGuiContext& g = *GImGui;
7239  ImGuiWindow* window = GetCurrentWindow();
7240  window->FontWindowScale = scale;
7242 }
7243 
7244 // User generally sees positions in window coordinates. Internally we store CursorPos in absolute screen coordinates because it is more convenient.
7245 // Conversion happens as we pass the value to user, but it makes our naming convention confusing because GetCursorPos() == (DC.CursorPos - window.Pos). May want to rename 'DC.CursorPos'.
7247 {
7248  ImGuiWindow* window = GetCurrentWindowRead();
7249  return window->DC.CursorPos - window->Pos + window->Scroll;
7250 }
7251 
7253 {
7254  ImGuiWindow* window = GetCurrentWindowRead();
7255  return window->DC.CursorPos.x - window->Pos.x + window->Scroll.x;
7256 }
7257 
7259 {
7260  ImGuiWindow* window = GetCurrentWindowRead();
7261  return window->DC.CursorPos.y - window->Pos.y + window->Scroll.y;
7262 }
7263 
7264 void ImGui::SetCursorPos(const ImVec2& local_pos)
7265 {
7266  ImGuiWindow* window = GetCurrentWindow();
7267  window->DC.CursorPos = window->Pos - window->Scroll + local_pos;
7268  window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);
7269 }
7270 
7272 {
7273  ImGuiWindow* window = GetCurrentWindow();
7274  window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + x;
7275  window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPos.x);
7276 }
7277 
7279 {
7280  ImGuiWindow* window = GetCurrentWindow();
7281  window->DC.CursorPos.y = window->Pos.y - window->Scroll.y + y;
7282  window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y);
7283 }
7284 
7286 {
7287  ImGuiWindow* window = GetCurrentWindowRead();
7288  return window->DC.CursorStartPos - window->Pos;
7289 }
7290 
7292 {
7293  ImGuiWindow* window = GetCurrentWindowRead();
7294  return window->DC.CursorPos;
7295 }
7296 
7297 void ImGui::SetCursorScreenPos(const ImVec2& screen_pos)
7298 {
7299  ImGuiWindow* window = GetCurrentWindow();
7300  window->DC.CursorPos = screen_pos;
7301  window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);
7302 }
7303 
7305 {
7306  return GImGui->CurrentWindow->Scroll.x;
7307 }
7308 
7310 {
7311  return GImGui->CurrentWindow->Scroll.y;
7312 }
7313 
7315 {
7316  return GetScrollMaxX(GImGui->CurrentWindow);
7317 }
7318 
7320 {
7321  return GetScrollMaxY(GImGui->CurrentWindow);
7322 }
7323 
7324 void ImGui::SetScrollX(float scroll_x)
7325 {
7326  ImGuiWindow* window = GetCurrentWindow();
7327  window->ScrollTarget.x = scroll_x;
7328  window->ScrollTargetCenterRatio.x = 0.0f;
7329 }
7330 
7331 void ImGui::SetScrollY(float scroll_y)
7332 {
7333  ImGuiWindow* window = GetCurrentWindow();
7334  window->ScrollTarget.y = scroll_y + window->TitleBarHeight() + window->MenuBarHeight(); // title bar height canceled out when using ScrollTargetRelY
7335  window->ScrollTargetCenterRatio.y = 0.0f;
7336 }
7337 
7338 void ImGui::SetScrollFromPosY(float pos_y, float center_y_ratio)
7339 {
7340  // We store a target position so centering can occur on the next frame when we are guaranteed to have a known window size
7341  ImGuiWindow* window = GetCurrentWindow();
7342  IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f);
7343  window->ScrollTarget.y = (float)(int)(pos_y + window->Scroll.y);
7344  window->ScrollTargetCenterRatio.y = center_y_ratio;
7345 }
7346 
7347 // center_y_ratio: 0.0f top of last item, 0.5f vertical center of last item, 1.0f bottom of last item.
7348 void ImGui::SetScrollHere(float center_y_ratio)
7349 {
7350  ImGuiWindow* window = GetCurrentWindow();
7351  float target_y = window->DC.CursorPosPrevLine.y - window->Pos.y; // Top of last item, in window space
7352  target_y += (window->DC.PrevLineHeight * center_y_ratio) + (GImGui->Style.ItemSpacing.y * (center_y_ratio - 0.5f) * 2.0f); // Precisely aim above, in the middle or below the last line.
7353  SetScrollFromPosY(target_y, center_y_ratio);
7354 }
7355 
7357 {
7358  ImGuiContext& g = *GImGui;
7359  g.NavNextActivateId = id;
7360 }
7361 
7363 {
7364  IM_ASSERT(offset >= -1); // -1 is allowed but not below
7365  ImGuiWindow* window = GetCurrentWindow();
7366  window->FocusIdxAllRequestNext = window->FocusIdxAllCounter + 1 + offset;
7367  window->FocusIdxTabRequestNext = INT_MAX;
7368 }
7369 
7371 {
7372  ImGuiContext& g = *GImGui;
7373  ImGuiWindow* window = g.CurrentWindow;
7374  if (!window->Appearing)
7375  return;
7376  if (g.NavWindow == window->RootWindowForNav && (g.NavInitRequest || g.NavInitResultId != 0) && g.NavLayer == g.NavWindow->DC.NavLayerCurrent)
7377  {
7378  g.NavInitRequest = false;
7381  NavUpdateAnyRequestFlag();
7382  if (!IsItemVisible())
7383  SetScrollHere();
7384  }
7385 }
7386 
7388 {
7389  ImGuiWindow* window = GetCurrentWindow();
7390  window->DC.StateStorage = tree ? tree : &window->StateStorage;
7391 }
7392 
7394 {
7395  ImGuiWindow* window = GetCurrentWindowRead();
7396  return window->DC.StateStorage;
7397 }
7398 
7399 void ImGui::TextV(const char* fmt, va_list args)
7400 {
7401  ImGuiWindow* window = GetCurrentWindow();
7402  if (window->SkipItems)
7403  return;
7404 
7405  ImGuiContext& g = *GImGui;
7406  const char* text_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args);
7407  TextUnformatted(g.TempBuffer, text_end);
7408 }
7409 
7410 void ImGui::Text(const char* fmt, ...)
7411 {
7412  va_list args;
7413  va_start(args, fmt);
7414  TextV(fmt, args);
7415  va_end(args);
7416 }
7417 
7418 void ImGui::TextColoredV(const ImVec4& col, const char* fmt, va_list args)
7419 {
7421  TextV(fmt, args);
7422  PopStyleColor();
7423 }
7424 
7425 void ImGui::TextColored(const ImVec4& col, const char* fmt, ...)
7426 {
7427  va_list args;
7428  va_start(args, fmt);
7429  TextColoredV(col, fmt, args);
7430  va_end(args);
7431 }
7432 
7433 void ImGui::TextDisabledV(const char* fmt, va_list args)
7434 {
7436  TextV(fmt, args);
7437  PopStyleColor();
7438 }
7439 
7440 void ImGui::TextDisabled(const char* fmt, ...)
7441 {
7442  va_list args;
7443  va_start(args, fmt);
7444  TextDisabledV(fmt, args);
7445  va_end(args);
7446 }
7447 
7448 void ImGui::TextWrappedV(const char* fmt, va_list args)
7449 {
7450  bool need_wrap = (GImGui->CurrentWindow->DC.TextWrapPos < 0.0f); // Keep existing wrap position is one ia already set
7451  if (need_wrap) PushTextWrapPos(0.0f);
7452  TextV(fmt, args);
7453  if (need_wrap) PopTextWrapPos();
7454 }
7455 
7456 void ImGui::TextWrapped(const char* fmt, ...)
7457 {
7458  va_list args;
7459  va_start(args, fmt);
7460  TextWrappedV(fmt, args);
7461  va_end(args);
7462 }
7463 
7464 void ImGui::TextUnformatted(const char* text, const char* text_end)
7465 {
7466  ImGuiWindow* window = GetCurrentWindow();
7467  if (window->SkipItems)
7468  return;
7469 
7470  ImGuiContext& g = *GImGui;
7471  IM_ASSERT(text != NULL);
7472  const char* text_begin = text;
7473  if (text_end == NULL)
7474  text_end = text + strlen(text); // FIXME-OPT
7475 
7476  const ImVec2 text_pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrentLineTextBaseOffset);
7477  const float wrap_pos_x = window->DC.TextWrapPos;
7478  const bool wrap_enabled = wrap_pos_x >= 0.0f;
7479  if (text_end - text > 2000 && !wrap_enabled)
7480  {
7481  // Long text!
7482  // Perform manual coarse clipping to optimize for long multi-line text
7483  // From this point we will only compute the width of lines that are visible. Optimization only available when word-wrapping is disabled.
7484  // We also don't vertically center the text within the line full height, which is unlikely to matter because we are likely the biggest and only item on the line.
7485  const char* line = text;
7486  const float line_height = GetTextLineHeight();
7487  const ImRect clip_rect = window->ClipRect;
7488  ImVec2 text_size(0,0);
7489 
7490  if (text_pos.y <= clip_rect.Max.y)
7491  {
7492  ImVec2 pos = text_pos;
7493 
7494  // Lines to skip (can't skip when logging text)
7495  if (!g.LogEnabled)
7496  {
7497  int lines_skippable = (int)((clip_rect.Min.y - text_pos.y) / line_height);
7498  if (lines_skippable > 0)
7499  {
7500  int lines_skipped = 0;
7501  while (line < text_end && lines_skipped < lines_skippable)
7502  {
7503  const char* line_end = strchr(line, '\n');
7504  if (!line_end)
7505  line_end = text_end;
7506  line = line_end + 1;
7507  lines_skipped++;
7508  }
7509  pos.y += lines_skipped * line_height;
7510  }
7511  }
7512 
7513  // Lines to render
7514  if (line < text_end)
7515  {
7516  ImRect line_rect(pos, pos + ImVec2(FLT_MAX, line_height));
7517  while (line < text_end)
7518  {
7519  const char* line_end = strchr(line, '\n');
7520  if (IsClippedEx(line_rect, 0, false))
7521  break;
7522 
7523  const ImVec2 line_size = CalcTextSize(line, line_end, false);
7524  text_size.x = ImMax(text_size.x, line_size.x);
7525  RenderText(pos, line, line_end, false);
7526  if (!line_end)
7527  line_end = text_end;
7528  line = line_end + 1;
7529  line_rect.Min.y += line_height;
7530  line_rect.Max.y += line_height;
7531  pos.y += line_height;
7532  }
7533 
7534  // Count remaining lines
7535  int lines_skipped = 0;
7536  while (line < text_end)
7537  {
7538  const char* line_end = strchr(line, '\n');
7539  if (!line_end)
7540  line_end = text_end;
7541  line = line_end + 1;
7542  lines_skipped++;
7543  }
7544  pos.y += lines_skipped * line_height;
7545  }
7546 
7547  text_size.y += (pos - text_pos).y;
7548  }
7549 
7550  ImRect bb(text_pos, text_pos + text_size);
7551  ItemSize(bb);
7552  ItemAdd(bb, 0);
7553  }
7554  else
7555  {
7556  const float wrap_width = wrap_enabled ? CalcWrapWidthForPos(window->DC.CursorPos, wrap_pos_x) : 0.0f;
7557  const ImVec2 text_size = CalcTextSize(text_begin, text_end, false, wrap_width);
7558 
7559  // Account of baseline offset
7560  ImRect bb(text_pos, text_pos + text_size);
7561  ItemSize(text_size);
7562  if (!ItemAdd(bb, 0))
7563  return;
7564 
7565  // Render (we don't hide text after ## in this end-user function)
7566  RenderTextWrapped(bb.Min, text_begin, text_end, wrap_width);
7567  }
7568 }
7569 
7571 {
7572  ImGuiWindow* window = GetCurrentWindow();
7573  if (window->SkipItems)
7574  return;
7575 
7576  ImGuiContext& g = *GImGui;
7577  window->DC.CurrentLineHeight = ImMax(window->DC.CurrentLineHeight, g.FontSize + g.Style.FramePadding.y * 2);
7579 }
7580 
7581 // Add a label+text combo aligned to other label+value widgets
7582 void ImGui::LabelTextV(const char* label, const char* fmt, va_list args)
7583 {
7584  ImGuiWindow* window = GetCurrentWindow();
7585  if (window->SkipItems)
7586  return;
7587 
7588  ImGuiContext& g = *GImGui;
7589  const ImGuiStyle& style = g.Style;
7590  const float w = CalcItemWidth();
7591 
7592  const ImVec2 label_size = CalcTextSize(label, NULL, true);
7593  const ImRect value_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2));
7594  const ImRect total_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w + (label_size.x > 0.0f ? style.ItemInnerSpacing.x : 0.0f), style.FramePadding.y*2) + label_size);
7595  ItemSize(total_bb, style.FramePadding.y);
7596  if (!ItemAdd(total_bb, 0))
7597  return;
7598 
7599  // Render
7600  const char* value_text_begin = &g.TempBuffer[0];
7601  const char* value_text_end = value_text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args);
7602  RenderTextClipped(value_bb.Min, value_bb.Max, value_text_begin, value_text_end, NULL, ImVec2(0.0f,0.5f));
7603  if (label_size.x > 0.0f)
7604  RenderText(ImVec2(value_bb.Max.x + style.ItemInnerSpacing.x, value_bb.Min.y + style.FramePadding.y), label);
7605 }
7606 
7607 void ImGui::LabelText(const char* label, const char* fmt, ...)
7608 {
7609  va_list args;
7610  va_start(args, fmt);
7611  LabelTextV(label, fmt, args);
7612  va_end(args);
7613 }
7614 
7615 bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags)
7616 {
7617  ImGuiContext& g = *GImGui;
7618  ImGuiWindow* window = GetCurrentWindow();
7619 
7620  if (flags & ImGuiButtonFlags_Disabled)
7621  {
7622  if (out_hovered) *out_hovered = false;
7623  if (out_held) *out_held = false;
7624  if (g.ActiveId == id) ClearActiveID();
7625  return false;
7626  }
7627 
7628  // Default behavior requires click+release on same spot
7631 
7632  ImGuiWindow* backup_hovered_window = g.HoveredWindow;
7633  if ((flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredRootWindow == window)
7634  g.HoveredWindow = window;
7635 
7636  bool pressed = false;
7637  bool hovered = ItemHoverable(bb, id);
7638 
7639  // Special mode for Drag and Drop where holding button pressed for a long time while dragging another item triggers the button
7642  {
7643  hovered = true;
7644  SetHoveredID(id);
7645  if (CalcTypematicPressedRepeatAmount(g.HoveredIdTimer + 0.0001f, g.HoveredIdTimer + 0.0001f - g.IO.DeltaTime, 0.01f, 0.70f)) // FIXME: Our formula for CalcTypematicPressedRepeatAmount() is fishy
7646  {
7647  pressed = true;
7648  FocusWindow(window);
7649  }
7650  }
7651 
7652  if ((flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredRootWindow == window)
7653  g.HoveredWindow = backup_hovered_window;
7654 
7655  // AllowOverlap mode (rarely used) requires previous frame HoveredId to be null or to match. This allows using patterns where a later submitted widget overlaps a previous one.
7656  if (hovered && (flags & ImGuiButtonFlags_AllowItemOverlap) && (g.HoveredIdPreviousFrame != id && g.HoveredIdPreviousFrame != 0))
7657  hovered = false;
7658 
7659  // Mouse
7660  if (hovered)
7661  {
7662  if (!(flags & ImGuiButtonFlags_NoKeyModifiers) || (!g.IO.KeyCtrl && !g.IO.KeyShift && !g.IO.KeyAlt))
7663  {
7664  // | CLICKING | HOLDING with ImGuiButtonFlags_Repeat
7665  // PressedOnClickRelease | <on release>* | <on repeat> <on repeat> .. (NOT on release) <-- MOST COMMON! (*) only if both click/release were over bounds
7666  // PressedOnClick | <on click> | <on click> <on repeat> <on repeat> ..
7667  // PressedOnRelease | <on release> | <on repeat> <on repeat> .. (NOT on release)
7668  // PressedOnDoubleClick | <on dclick> | <on dclick> <on repeat> <on repeat> ..
7669  // FIXME-NAV: We don't honor those different behaviors.
7671  {
7672  SetActiveID(id, window);
7673  if (!(flags & ImGuiButtonFlags_NoNavFocus))
7674  SetFocusID(id, window);
7675  FocusWindow(window);
7676  }
7678  {
7679  pressed = true;
7681  ClearActiveID();
7682  else
7683  SetActiveID(id, window); // Hold on ID
7684  FocusWindow(window);
7685  }
7686  if ((flags & ImGuiButtonFlags_PressedOnRelease) && g.IO.MouseReleased[0])
7687  {
7688  if (!((flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[0] >= g.IO.KeyRepeatDelay)) // Repeat mode trumps <on release>
7689  pressed = true;
7690  ClearActiveID();
7691  }
7692 
7693  // 'Repeat' mode acts when held regardless of _PressedOn flags (see table above).
7694  // Relies on repeat logic of IsMouseClicked() but we may as well do it ourselves if we end up exposing finer RepeatDelay/RepeatRate settings.
7695  if ((flags & ImGuiButtonFlags_Repeat) && g.ActiveId == id && g.IO.MouseDownDuration[0] > 0.0f && IsMouseClicked(0, true))
7696  pressed = true;
7697  }
7698 
7699  if (pressed)
7700  g.NavDisableHighlight = true;
7701  }
7702 
7703  // Gamepad/Keyboard navigation
7704  // We report navigated item as hovered but we don't set g.HoveredId to not interfere with mouse.
7705  if (g.NavId == id && !g.NavDisableHighlight && g.NavDisableMouseHover && (g.ActiveId == 0 || g.ActiveId == id || g.ActiveId == window->MoveId))
7706  hovered = true;
7707 
7708  if (g.NavActivateDownId == id)
7709  {
7710  bool nav_activated_by_code = (g.NavActivateId == id);
7711  bool nav_activated_by_inputs = IsNavInputPressed(ImGuiNavInput_Activate, (flags & ImGuiButtonFlags_Repeat) ? ImGuiInputReadMode_Repeat : ImGuiInputReadMode_Pressed);
7712  if (nav_activated_by_code || nav_activated_by_inputs)
7713  pressed = true;
7714  if (nav_activated_by_code || nav_activated_by_inputs || g.ActiveId == id)
7715  {
7716  // Set active id so it can be queried by user via IsItemActive(), equivalent of holding the mouse button.
7717  g.NavActivateId = id; // This is so SetActiveId assign a Nav source
7718  SetActiveID(id, window);
7719  if (!(flags & ImGuiButtonFlags_NoNavFocus))
7720  SetFocusID(id, window);
7721  g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right) | (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down);
7722  }
7723  }
7724 
7725  bool held = false;
7726  if (g.ActiveId == id)
7727  {
7729  {
7731  g.ActiveIdClickOffset = g.IO.MousePos - bb.Min;
7732  if (g.IO.MouseDown[0])
7733  {
7734  held = true;
7735  }
7736  else
7737  {
7738  if (hovered && (flags & ImGuiButtonFlags_PressedOnClickRelease))
7739  if (!((flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[0] >= g.IO.KeyRepeatDelay)) // Repeat mode trumps <on release>
7740  if (!g.DragDropActive)
7741  pressed = true;
7742  ClearActiveID();
7743  }
7744  if (!(flags & ImGuiButtonFlags_NoNavFocus))
7745  g.NavDisableHighlight = true;
7746  }
7747  else if (g.ActiveIdSource == ImGuiInputSource_Nav)
7748  {
7749  if (g.NavActivateDownId != id)
7750  ClearActiveID();
7751  }
7752  }
7753 
7754  if (out_hovered) *out_hovered = hovered;
7755  if (out_held) *out_held = held;
7756 
7757  return pressed;
7758 }
7759 
7760 bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags flags)
7761 {
7762  ImGuiWindow* window = GetCurrentWindow();
7763  if (window->SkipItems)
7764  return false;
7765 
7766  ImGuiContext& g = *GImGui;
7767  const ImGuiStyle& style = g.Style;
7768  const ImGuiID id = window->GetID(label);
7769  const ImVec2 label_size = CalcTextSize(label, NULL, true);
7770 
7771  ImVec2 pos = window->DC.CursorPos;
7772  if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrentLineTextBaseOffset) // Try to vertically align buttons that are smaller/have no padding so that text baseline matches (bit hacky, since it shouldn't be a flag)
7773  pos.y += window->DC.CurrentLineTextBaseOffset - style.FramePadding.y;
7774  ImVec2 size = CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0f, label_size.y + style.FramePadding.y * 2.0f);
7775 
7776  const ImRect bb(pos, pos + size);
7777  ItemSize(bb, style.FramePadding.y);
7778  if (!ItemAdd(bb, id))
7779  return false;
7780 
7782  flags |= ImGuiButtonFlags_Repeat;
7783  bool hovered, held;
7784  bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags);
7785 
7786  // Render
7787  const ImU32 col = GetColorU32((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
7788  RenderNavHighlight(bb, id);
7789  RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding);
7790  RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, NULL, &label_size, style.ButtonTextAlign, &bb);
7791 
7792  // Automatically close popups
7793  //if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup))
7794  // CloseCurrentPopup();
7795 
7796  return pressed;
7797 }
7798 
7799 bool ImGui::Button(const char* label, const ImVec2& size_arg)
7800 {
7801  return ButtonEx(label, size_arg, 0);
7802 }
7803 
7804 // Small buttons fits within text without additional vertical spacing.
7805 bool ImGui::SmallButton(const char* label)
7806 {
7807  ImGuiContext& g = *GImGui;
7808  float backup_padding_y = g.Style.FramePadding.y;
7809  g.Style.FramePadding.y = 0.0f;
7810  bool pressed = ButtonEx(label, ImVec2(0,0), ImGuiButtonFlags_AlignTextBaseLine);
7811  g.Style.FramePadding.y = backup_padding_y;
7812  return pressed;
7813 }
7814 
7815 bool ImGui::ArrowButton(const char* str_id, ImGuiDir dir)
7816 {
7817  ImGuiWindow* window = GetCurrentWindow();
7818  if (window->SkipItems)
7819  return false;
7820 
7821  ImGuiContext& g = *GImGui;
7822  const ImGuiID id = window->GetID(str_id);
7823  float sz = ImGui::GetFrameHeight();
7824  const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(sz, sz));
7825  ItemSize(bb);
7826  if (!ItemAdd(bb, id))
7827  return false;
7828 
7829  bool hovered, held;
7830  bool pressed = ButtonBehavior(bb, id, &hovered, &held);
7831 
7832  // Render
7833  const ImU32 col = GetColorU32((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
7834  RenderNavHighlight(bb, id);
7835  RenderFrame(bb.Min, bb.Max, col, true, g.Style.FrameRounding);
7836  RenderArrow(bb.Min + g.Style.FramePadding, dir);
7837 
7838  return pressed;
7839 }
7840 
7841 // Tip: use ImGui::PushID()/PopID() to push indices or pointers in the ID stack.
7842 // Then you can keep 'str_id' empty or the same for all your buttons (instead of creating a string based on a non-string id)
7843 bool ImGui::InvisibleButton(const char* str_id, const ImVec2& size_arg)
7844 {
7845  ImGuiWindow* window = GetCurrentWindow();
7846  if (window->SkipItems)
7847  return false;
7848 
7849  const ImGuiID id = window->GetID(str_id);
7850  ImVec2 size = CalcItemSize(size_arg, 0.0f, 0.0f);
7851  const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);
7852  ItemSize(bb);
7853  if (!ItemAdd(bb, id))
7854  return false;
7855 
7856  bool hovered, held;
7857  bool pressed = ButtonBehavior(bb, id, &hovered, &held);
7858 
7859  return pressed;
7860 }
7861 
7862 // Button to close a window
7863 bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos, float radius)
7864 {
7865  ImGuiContext& g = *GImGui;
7866  ImGuiWindow* window = g.CurrentWindow;
7867 
7868  // We intentionally allow interaction when clipped so that a mechanical Alt,Right,Validate sequence close a window.
7869  // (this isn't the regular behavior of buttons, but it doesn't affect the user much because navigation tends to keep items visible).
7870  const ImRect bb(pos - ImVec2(radius,radius), pos + ImVec2(radius,radius));
7871  bool is_clipped = !ItemAdd(bb, id);
7872 
7873  bool hovered, held;
7874  bool pressed = ButtonBehavior(bb, id, &hovered, &held);
7875  if (is_clipped)
7876  return pressed;
7877 
7878  // Render
7879  ImVec2 center = bb.GetCenter();
7880  if (hovered)
7881  window->DrawList->AddCircleFilled(center, ImMax(2.0f, radius), GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered), 9);
7882 
7883  float cross_extent = (radius * 0.7071f) - 1.0f;
7884  ImU32 cross_col = GetColorU32(ImGuiCol_Text);
7885  center -= ImVec2(0.5f, 0.5f);
7886  window->DrawList->AddLine(center + ImVec2(+cross_extent,+cross_extent), center + ImVec2(-cross_extent,-cross_extent), cross_col, 1.0f);
7887  window->DrawList->AddLine(center + ImVec2(+cross_extent,-cross_extent), center + ImVec2(-cross_extent,+cross_extent), cross_col, 1.0f);
7888 
7889  return pressed;
7890 }
7891 
7892 void ImGui::Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col)
7893 {
7894  ImGuiWindow* window = GetCurrentWindow();
7895  if (window->SkipItems)
7896  return;
7897 
7898  ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);
7899  if (border_col.w > 0.0f)
7900  bb.Max += ImVec2(2,2);
7901  ItemSize(bb);
7902  if (!ItemAdd(bb, 0))
7903  return;
7904 
7905  if (border_col.w > 0.0f)
7906  {
7907  window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(border_col), 0.0f);
7908  window->DrawList->AddImage(user_texture_id, bb.Min+ImVec2(1,1), bb.Max-ImVec2(1,1), uv0, uv1, GetColorU32(tint_col));
7909  }
7910  else
7911  {
7912  window->DrawList->AddImage(user_texture_id, bb.Min, bb.Max, uv0, uv1, GetColorU32(tint_col));
7913  }
7914 }
7915 
7916 // frame_padding < 0: uses FramePadding from style (default)
7917 // frame_padding = 0: no framing
7918 // frame_padding > 0: set framing size
7919 // The color used are the button colors.
7920 bool ImGui::ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, int frame_padding, const ImVec4& bg_col, const ImVec4& tint_col)
7921 {
7922  ImGuiWindow* window = GetCurrentWindow();
7923  if (window->SkipItems)
7924  return false;
7925 
7926  ImGuiContext& g = *GImGui;
7927  const ImGuiStyle& style = g.Style;
7928 
7929  // Default to using texture ID as ID. User can still push string/integer prefixes.
7930  // We could hash the size/uv to create a unique ID but that would prevent the user from animating UV.
7931  PushID((void *)user_texture_id);
7932  const ImGuiID id = window->GetID("#image");
7933  PopID();
7934 
7935  const ImVec2 padding = (frame_padding >= 0) ? ImVec2((float)frame_padding, (float)frame_padding) : style.FramePadding;
7936  const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size + padding*2);
7937  const ImRect image_bb(window->DC.CursorPos + padding, window->DC.CursorPos + padding + size);
7938  ItemSize(bb);
7939  if (!ItemAdd(bb, id))
7940  return false;
7941 
7942  bool hovered, held;
7943  bool pressed = ButtonBehavior(bb, id, &hovered, &held);
7944 
7945  // Render
7946  const ImU32 col = GetColorU32((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
7947  RenderNavHighlight(bb, id);
7948  RenderFrame(bb.Min, bb.Max, col, true, ImClamp((float)ImMin(padding.x, padding.y), 0.0f, style.FrameRounding));
7949  if (bg_col.w > 0.0f)
7950  window->DrawList->AddRectFilled(image_bb.Min, image_bb.Max, GetColorU32(bg_col));
7951  window->DrawList->AddImage(user_texture_id, image_bb.Min, image_bb.Max, uv0, uv1, GetColorU32(tint_col));
7952 
7953  return pressed;
7954 }
7955 
7956 // Start logging ImGui output to TTY
7957 void ImGui::LogToTTY(int max_depth)
7958 {
7959  ImGuiContext& g = *GImGui;
7960  if (g.LogEnabled)
7961  return;
7962  ImGuiWindow* window = g.CurrentWindow;
7963 
7964  IM_ASSERT(g.LogFile == NULL);
7965  g.LogFile = stdout;
7966  g.LogEnabled = true;
7967  g.LogStartDepth = window->DC.TreeDepth;
7968  if (max_depth >= 0)
7969  g.LogAutoExpandMaxDepth = max_depth;
7970 }
7971 
7972 // Start logging ImGui output to given file
7973 void ImGui::LogToFile(int max_depth, const char* filename)
7974 {
7975  ImGuiContext& g = *GImGui;
7976  if (g.LogEnabled)
7977  return;
7978  ImGuiWindow* window = g.CurrentWindow;
7979 
7980  if (!filename)
7981  {
7982  filename = g.IO.LogFilename;
7983  if (!filename)
7984  return;
7985  }
7986 
7987  IM_ASSERT(g.LogFile == NULL);
7988  g.LogFile = ImFileOpen(filename, "ab");
7989  if (!g.LogFile)
7990  {
7991  IM_ASSERT(g.LogFile != NULL); // Consider this an error
7992  return;
7993  }
7994  g.LogEnabled = true;
7995  g.LogStartDepth = window->DC.TreeDepth;
7996  if (max_depth >= 0)
7997  g.LogAutoExpandMaxDepth = max_depth;
7998 }
7999 
8000 // Start logging ImGui output to clipboard
8001 void ImGui::LogToClipboard(int max_depth)
8002 {
8003  ImGuiContext& g = *GImGui;
8004  if (g.LogEnabled)
8005  return;
8006  ImGuiWindow* window = g.CurrentWindow;
8007 
8008  IM_ASSERT(g.LogFile == NULL);
8009  g.LogFile = NULL;
8010  g.LogEnabled = true;
8011  g.LogStartDepth = window->DC.TreeDepth;
8012  if (max_depth >= 0)
8013  g.LogAutoExpandMaxDepth = max_depth;
8014 }
8015 
8017 {
8018  ImGuiContext& g = *GImGui;
8019  if (!g.LogEnabled)
8020  return;
8021 
8023  if (g.LogFile != NULL)
8024  {
8025  if (g.LogFile == stdout)
8026  fflush(g.LogFile);
8027  else
8028  fclose(g.LogFile);
8029  g.LogFile = NULL;
8030  }
8031  if (g.LogClipboard.size() > 1)
8032  {
8034  g.LogClipboard.clear();
8035  }
8036  g.LogEnabled = false;
8037 }
8038 
8039 // Helper to display logging buttons
8041 {
8042  ImGuiContext& g = *GImGui;
8043 
8044  PushID("LogButtons");
8045  const bool log_to_tty = Button("Log To TTY"); SameLine();
8046  const bool log_to_file = Button("Log To File"); SameLine();
8047  const bool log_to_clipboard = Button("Log To Clipboard"); SameLine();
8048  PushItemWidth(80.0f);
8049  PushAllowKeyboardFocus(false);
8050  SliderInt("Depth", &g.LogAutoExpandMaxDepth, 0, 9, NULL);
8052  PopItemWidth();
8053  PopID();
8054 
8055  // Start logging at the end of the function so that the buttons don't appear in the log
8056  if (log_to_tty)
8058  if (log_to_file)
8060  if (log_to_clipboard)
8062 }
8063 
8065 {
8066  if (flags & ImGuiTreeNodeFlags_Leaf)
8067  return true;
8068 
8069  // We only write to the tree storage if the user clicks (or explicitly use SetNextTreeNode*** functions)
8070  ImGuiContext& g = *GImGui;
8071  ImGuiWindow* window = g.CurrentWindow;
8072  ImGuiStorage* storage = window->DC.StateStorage;
8073 
8074  bool is_open;
8075  if (g.NextTreeNodeOpenCond != 0)
8076  {
8078  {
8079  is_open = g.NextTreeNodeOpenVal;
8080  storage->SetInt(id, is_open);
8081  }
8082  else
8083  {
8084  // We treat ImGuiCond_Once and ImGuiCond_FirstUseEver the same because tree node state are not saved persistently.
8085  const int stored_value = storage->GetInt(id, -1);
8086  if (stored_value == -1)
8087  {
8088  is_open = g.NextTreeNodeOpenVal;
8089  storage->SetInt(id, is_open);
8090  }
8091  else
8092  {
8093  is_open = stored_value != 0;
8094  }
8095  }
8096  g.NextTreeNodeOpenCond = 0;
8097  }
8098  else
8099  {
8100  is_open = storage->GetInt(id, (flags & ImGuiTreeNodeFlags_DefaultOpen) ? 1 : 0) != 0;
8101  }
8102 
8103  // When logging is enabled, we automatically expand tree nodes (but *NOT* collapsing headers.. seems like sensible behavior).
8104  // NB- If we are above max depth we still allow manually opened nodes to be logged.
8106  is_open = true;
8107 
8108  return is_open;
8109 }
8110 
8111 bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end)
8112 {
8113  ImGuiWindow* window = GetCurrentWindow();
8114  if (window->SkipItems)
8115  return false;
8116 
8117  ImGuiContext& g = *GImGui;
8118  const ImGuiStyle& style = g.Style;
8119  const bool display_frame = (flags & ImGuiTreeNodeFlags_Framed) != 0;
8120  const ImVec2 padding = (display_frame || (flags & ImGuiTreeNodeFlags_FramePadding)) ? style.FramePadding : ImVec2(style.FramePadding.x, 0.0f);
8121 
8122  if (!label_end)
8123  label_end = FindRenderedTextEnd(label);
8124  const ImVec2 label_size = CalcTextSize(label, label_end, false);
8125 
8126  // We vertically grow up to current line height up the typical widget height.
8127  const float text_base_offset_y = ImMax(padding.y, window->DC.CurrentLineTextBaseOffset); // Latch before ItemSize changes it
8128  const float frame_height = ImMax(ImMin(window->DC.CurrentLineHeight, g.FontSize + style.FramePadding.y*2), label_size.y + padding.y*2);
8129  ImRect frame_bb = ImRect(window->DC.CursorPos, ImVec2(window->Pos.x + GetContentRegionMax().x, window->DC.CursorPos.y + frame_height));
8130  if (display_frame)
8131  {
8132  // Framed header expand a little outside the default padding
8133  frame_bb.Min.x -= (float)(int)(window->WindowPadding.x*0.5f) - 1;
8134  frame_bb.Max.x += (float)(int)(window->WindowPadding.x*0.5f) - 1;
8135  }
8136 
8137  const float text_offset_x = (g.FontSize + (display_frame ? padding.x*3 : padding.x*2)); // Collapser arrow width + Spacing
8138  const float text_width = g.FontSize + (label_size.x > 0.0f ? label_size.x + padding.x*2 : 0.0f); // Include collapser
8139  ItemSize(ImVec2(text_width, frame_height), text_base_offset_y);
8140 
8141  // For regular tree nodes, we arbitrary allow to click past 2 worth of ItemSpacing
8142  // (Ideally we'd want to add a flag for the user to specify if we want the hit test to be done up to the right side of the content or not)
8143  const ImRect interact_bb = display_frame ? frame_bb : ImRect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + text_width + style.ItemSpacing.x*2, frame_bb.Max.y);
8144  bool is_open = TreeNodeBehaviorIsOpen(id, flags);
8145 
8146  // Store a flag for the current depth to tell if we will allow closing this node when navigating one of its child.
8147  // For this purpose we essentially compare if g.NavIdIsAlive went from 0 to 1 between TreeNode() and TreePop().
8148  // This is currently only support 32 level deep and we are fine with (1 << Depth) overflowing into a zero.
8150  window->DC.TreeDepthMayJumpToParentOnPop |= (1 << window->DC.TreeDepth);
8151 
8152  bool item_add = ItemAdd(interact_bb, id);
8154  window->DC.LastItemDisplayRect = frame_bb;
8155 
8156  if (!item_add)
8157  {
8158  if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
8159  TreePushRawID(id);
8160  return is_open;
8161  }
8162 
8163  // Flags that affects opening behavior:
8164  // - 0(default) ..................... single-click anywhere to open
8165  // - OpenOnDoubleClick .............. double-click anywhere to open
8166  // - OpenOnArrow .................... single-click on arrow to open
8167  // - OpenOnDoubleClick|OpenOnArrow .. single-click on arrow or double-click anywhere to open
8169  if (!(flags & ImGuiTreeNodeFlags_Leaf))
8173 
8174  bool hovered, held, pressed = ButtonBehavior(interact_bb, id, &hovered, &held, button_flags);
8175  if (!(flags & ImGuiTreeNodeFlags_Leaf))
8176  {
8177  bool toggled = false;
8178  if (pressed)
8179  {
8181  if (flags & ImGuiTreeNodeFlags_OpenOnArrow)
8182  toggled |= IsMouseHoveringRect(interact_bb.Min, ImVec2(interact_bb.Min.x + text_offset_x, interact_bb.Max.y)) && (!g.NavDisableMouseHover);
8183  if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick)
8184  toggled |= g.IO.MouseDoubleClicked[0];
8185  if (g.DragDropActive && is_open) // When using Drag and Drop "hold to open" we keep the node highlighted after opening, but never close it again.
8186  toggled = false;
8187  }
8188 
8189  if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Left && is_open)
8190  {
8191  toggled = true;
8193  }
8194  if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Right && !is_open) // If there's something upcoming on the line we may want to give it the priority?
8195  {
8196  toggled = true;
8198  }
8199 
8200  if (toggled)
8201  {
8202  is_open = !is_open;
8203  window->DC.StateStorage->SetInt(id, is_open);
8204  }
8205  }
8208 
8209  // Render
8210  const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
8211  const ImVec2 text_pos = frame_bb.Min + ImVec2(text_offset_x, text_base_offset_y);
8212  if (display_frame)
8213  {
8214  // Framed type
8215  RenderFrame(frame_bb.Min, frame_bb.Max, col, true, style.FrameRounding);
8217  RenderArrow(frame_bb.Min + ImVec2(padding.x, text_base_offset_y), is_open ? ImGuiDir_Down : ImGuiDir_Right, 1.0f);
8218  if (g.LogEnabled)
8219  {
8220  // NB: '##' is normally used to hide text (as a library-wide feature), so we need to specify the text range to make sure the ## aren't stripped out here.
8221  const char log_prefix[] = "\n##";
8222  const char log_suffix[] = "##";
8223  LogRenderedText(&text_pos, log_prefix, log_prefix+3);
8224  RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size);
8225  LogRenderedText(&text_pos, log_suffix+1, log_suffix+3);
8226  }
8227  else
8228  {
8229  RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size);
8230  }
8231  }
8232  else
8233  {
8234  // Unframed typed for tree nodes
8235  if (hovered || (flags & ImGuiTreeNodeFlags_Selected))
8236  {
8237  RenderFrame(frame_bb.Min, frame_bb.Max, col, false);
8239  }
8240 
8241  if (flags & ImGuiTreeNodeFlags_Bullet)
8242  RenderBullet(frame_bb.Min + ImVec2(text_offset_x * 0.5f, g.FontSize*0.50f + text_base_offset_y));
8243  else if (!(flags & ImGuiTreeNodeFlags_Leaf))
8244  RenderArrow(frame_bb.Min + ImVec2(padding.x, g.FontSize*0.15f + text_base_offset_y), is_open ? ImGuiDir_Down : ImGuiDir_Right, 0.70f);
8245  if (g.LogEnabled)
8246  LogRenderedText(&text_pos, ">");
8247  RenderText(text_pos, label, label_end, false);
8248  }
8249 
8250  if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
8251  TreePushRawID(id);
8252  return is_open;
8253 }
8254 
8255 // CollapsingHeader returns true when opened but do not indent nor push into the ID stack (because of the ImGuiTreeNodeFlags_NoTreePushOnOpen flag).
8256 // This is basically the same as calling TreeNodeEx(label, ImGuiTreeNodeFlags_CollapsingHeader | ImGuiTreeNodeFlags_NoTreePushOnOpen). You can remove the _NoTreePushOnOpen flag if you want behavior closer to normal TreeNode().
8258 {
8259  ImGuiWindow* window = GetCurrentWindow();
8260  if (window->SkipItems)
8261  return false;
8262 
8264 }
8265 
8266 bool ImGui::CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags flags)
8267 {
8268  ImGuiWindow* window = GetCurrentWindow();
8269  if (window->SkipItems)
8270  return false;
8271 
8272  if (p_open && !*p_open)
8273  return false;
8274 
8275  ImGuiID id = window->GetID(label);
8277  if (p_open)
8278  {
8279  // Create a small overlapping close button // FIXME: We can evolve this into user accessible helpers to add extra buttons on title bars, headers, etc.
8280  ImGuiContext& g = *GImGui;
8281  float button_sz = g.FontSize * 0.5f;
8282  ImGuiItemHoveredDataBackup last_item_backup;
8283  if (CloseButton(window->GetID((void*)(intptr_t)(id+1)), ImVec2(ImMin(window->DC.LastItemRect.Max.x, window->ClipRect.Max.x) - g.Style.FramePadding.x - button_sz, window->DC.LastItemRect.Min.y + g.Style.FramePadding.y + button_sz), button_sz))
8284  *p_open = false;
8285  last_item_backup.Restore();
8286  }
8287 
8288  return is_open;
8289 }
8290 
8292 {
8293  ImGuiWindow* window = GetCurrentWindow();
8294  if (window->SkipItems)
8295  return false;
8296 
8297  return TreeNodeBehavior(window->GetID(label), flags, label, NULL);
8298 }
8299 
8300 bool ImGui::TreeNodeExV(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args)
8301 {
8302  ImGuiWindow* window = GetCurrentWindow();
8303  if (window->SkipItems)
8304  return false;
8305 
8306  ImGuiContext& g = *GImGui;
8307  const char* label_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args);
8308  return TreeNodeBehavior(window->GetID(str_id), flags, g.TempBuffer, label_end);
8309 }
8310 
8311 bool ImGui::TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args)
8312 {
8313  ImGuiWindow* window = GetCurrentWindow();
8314  if (window->SkipItems)
8315  return false;
8316 
8317  ImGuiContext& g = *GImGui;
8318  const char* label_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args);
8319  return TreeNodeBehavior(window->GetID(ptr_id), flags, g.TempBuffer, label_end);
8320 }
8321 
8322 bool ImGui::TreeNodeV(const char* str_id, const char* fmt, va_list args)
8323 {
8324  return TreeNodeExV(str_id, 0, fmt, args);
8325 }
8326 
8327 bool ImGui::TreeNodeV(const void* ptr_id, const char* fmt, va_list args)
8328 {
8329  return TreeNodeExV(ptr_id, 0, fmt, args);
8330 }
8331 
8332 bool ImGui::TreeNodeEx(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, ...)
8333 {
8334  va_list args;
8335  va_start(args, fmt);
8336  bool is_open = TreeNodeExV(str_id, flags, fmt, args);
8337  va_end(args);
8338  return is_open;
8339 }
8340 
8341 bool ImGui::TreeNodeEx(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, ...)
8342 {
8343  va_list args;
8344  va_start(args, fmt);
8345  bool is_open = TreeNodeExV(ptr_id, flags, fmt, args);
8346  va_end(args);
8347  return is_open;
8348 }
8349 
8350 bool ImGui::TreeNode(const char* str_id, const char* fmt, ...)
8351 {
8352  va_list args;
8353  va_start(args, fmt);
8354  bool is_open = TreeNodeExV(str_id, 0, fmt, args);
8355  va_end(args);
8356  return is_open;
8357 }
8358 
8359 bool ImGui::TreeNode(const void* ptr_id, const char* fmt, ...)
8360 {
8361  va_list args;
8362  va_start(args, fmt);
8363  bool is_open = TreeNodeExV(ptr_id, 0, fmt, args);
8364  va_end(args);
8365  return is_open;
8366 }
8367 
8368 bool ImGui::TreeNode(const char* label)
8369 {
8370  ImGuiWindow* window = GetCurrentWindow();
8371  if (window->SkipItems)
8372  return false;
8373  return TreeNodeBehavior(window->GetID(label), 0, label, NULL);
8374 }
8375 
8377 {
8378  ImGuiContext& g = *GImGui;
8380 }
8381 
8382 // Horizontal distance preceding label when using TreeNode() or Bullet()
8384 {
8385  ImGuiContext& g = *GImGui;
8386  return g.FontSize + (g.Style.FramePadding.x * 2.0f);
8387 }
8388 
8389 void ImGui::SetNextTreeNodeOpen(bool is_open, ImGuiCond cond)
8390 {
8391  ImGuiContext& g = *GImGui;
8392  if (g.CurrentWindow->SkipItems)
8393  return;
8394  g.NextTreeNodeOpenVal = is_open;
8395  g.NextTreeNodeOpenCond = cond ? cond : ImGuiCond_Always;
8396 }
8397 
8398 void ImGui::PushID(const char* str_id)
8399 {
8400  ImGuiWindow* window = GetCurrentWindowRead();
8401  window->IDStack.push_back(window->GetID(str_id));
8402 }
8403 
8404 void ImGui::PushID(const char* str_id_begin, const char* str_id_end)
8405 {
8406  ImGuiWindow* window = GetCurrentWindowRead();
8407  window->IDStack.push_back(window->GetID(str_id_begin, str_id_end));
8408 }
8409 
8410 void ImGui::PushID(const void* ptr_id)
8411 {
8412  ImGuiWindow* window = GetCurrentWindowRead();
8413  window->IDStack.push_back(window->GetID(ptr_id));
8414 }
8415 
8416 void ImGui::PushID(int int_id)
8417 {
8418  const void* ptr_id = (void*)(intptr_t)int_id;
8419  ImGuiWindow* window = GetCurrentWindowRead();
8420  window->IDStack.push_back(window->GetID(ptr_id));
8421 }
8422 
8424 {
8425  ImGuiWindow* window = GetCurrentWindowRead();
8426  window->IDStack.pop_back();
8427 }
8428 
8429 ImGuiID ImGui::GetID(const char* str_id)
8430 {
8431  return GImGui->CurrentWindow->GetID(str_id);
8432 }
8433 
8434 ImGuiID ImGui::GetID(const char* str_id_begin, const char* str_id_end)
8435 {
8436  return GImGui->CurrentWindow->GetID(str_id_begin, str_id_end);
8437 }
8438 
8439 ImGuiID ImGui::GetID(const void* ptr_id)
8440 {
8441  return GImGui->CurrentWindow->GetID(ptr_id);
8442 }
8443 
8445 {
8446  ImGuiWindow* window = GetCurrentWindow();
8447  if (window->SkipItems)
8448  return;
8449 
8450  ImGuiContext& g = *GImGui;
8451  const ImGuiStyle& style = g.Style;
8452  const float line_height = ImMax(ImMin(window->DC.CurrentLineHeight, g.FontSize + g.Style.FramePadding.y*2), g.FontSize);
8453  const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize, line_height));
8454  ItemSize(bb);
8455  if (!ItemAdd(bb, 0))
8456  {
8457  SameLine(0, style.FramePadding.x*2);
8458  return;
8459  }
8460 
8461  // Render and stay on same line
8462  RenderBullet(bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f));
8463  SameLine(0, style.FramePadding.x*2);
8464 }
8465 
8466 // Text with a little bullet aligned to the typical tree node.
8467 void ImGui::BulletTextV(const char* fmt, va_list args)
8468 {
8469  ImGuiWindow* window = GetCurrentWindow();
8470  if (window->SkipItems)
8471  return;
8472 
8473  ImGuiContext& g = *GImGui;
8474  const ImGuiStyle& style = g.Style;
8475 
8476  const char* text_begin = g.TempBuffer;
8477  const char* text_end = text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args);
8478  const ImVec2 label_size = CalcTextSize(text_begin, text_end, false);
8479  const float text_base_offset_y = ImMax(0.0f, window->DC.CurrentLineTextBaseOffset); // Latch before ItemSize changes it
8480  const float line_height = ImMax(ImMin(window->DC.CurrentLineHeight, g.FontSize + g.Style.FramePadding.y*2), g.FontSize);
8481  const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize + (label_size.x > 0.0f ? (label_size.x + style.FramePadding.x*2) : 0.0f), ImMax(line_height, label_size.y))); // Empty text doesn't add padding
8482  ItemSize(bb);
8483  if (!ItemAdd(bb, 0))
8484  return;
8485 
8486  // Render
8487  RenderBullet(bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f));
8488  RenderText(bb.Min+ImVec2(g.FontSize + style.FramePadding.x*2, text_base_offset_y), text_begin, text_end, false);
8489 }
8490 
8491 void ImGui::BulletText(const char* fmt, ...)
8492 {
8493  va_list args;
8494  va_start(args, fmt);
8495  BulletTextV(fmt, args);
8496  va_end(args);
8497 }
8498 
8499 static inline int DataTypeFormatString(char* buf, int buf_size, ImGuiDataType data_type, const void* data_ptr, const char* format)
8500 {
8501  if (data_type == ImGuiDataType_S32 || data_type == ImGuiDataType_U32) // Signedness doesn't matter when pushing the argument
8502  return ImFormatString(buf, buf_size, format, *(const ImU32*)data_ptr);
8503  if (data_type == ImGuiDataType_S64 || data_type == ImGuiDataType_U64) // Signedness doesn't matter when pushing the argument
8504  return ImFormatString(buf, buf_size, format, *(const ImU64*)data_ptr);
8505  if (data_type == ImGuiDataType_Float)
8506  return ImFormatString(buf, buf_size, format, *(const float*)data_ptr);
8507  if (data_type == ImGuiDataType_Double)
8508  return ImFormatString(buf, buf_size, format, *(const double*)data_ptr);
8509  IM_ASSERT(0);
8510  return 0;
8511 }
8512 
8513 // FIXME: Adding support for clamping on boundaries of the data type would be nice.
8514 static void DataTypeApplyOp(ImGuiDataType data_type, int op, void* output, void* arg1, const void* arg2)
8515 {
8516  IM_ASSERT(op == '+' || op == '-');
8517  switch (data_type)
8518  {
8519  case ImGuiDataType_S32:
8520  if (op == '+') *(int*)output = *(const int*)arg1 + *(const int*)arg2;
8521  else if (op == '-') *(int*)output = *(const int*)arg1 - *(const int*)arg2;
8522  return;
8523  case ImGuiDataType_U32:
8524  if (op == '+') *(unsigned int*)output = *(const unsigned int*)arg1 + *(const ImU32*)arg2;
8525  else if (op == '-') *(unsigned int*)output = *(const unsigned int*)arg1 - *(const ImU32*)arg2;
8526  return;
8527  case ImGuiDataType_S64:
8528  if (op == '+') *(ImS64*)output = *(const ImS64*)arg1 + *(const ImS64*)arg2;
8529  else if (op == '-') *(ImS64*)output = *(const ImS64*)arg1 - *(const ImS64*)arg2;
8530  return;
8531  case ImGuiDataType_U64:
8532  if (op == '+') *(ImU64*)output = *(const ImU64*)arg1 + *(const ImU64*)arg2;
8533  else if (op == '-') *(ImU64*)output = *(const ImU64*)arg1 - *(const ImU64*)arg2;
8534  return;
8535  case ImGuiDataType_Float:
8536  if (op == '+') *(float*)output = *(const float*)arg1 + *(const float*)arg2;
8537  else if (op == '-') *(float*)output = *(const float*)arg1 - *(const float*)arg2;
8538  return;
8539  case ImGuiDataType_Double:
8540  if (op == '+') *(double*)output = *(const double*)arg1 + *(const double*)arg2;
8541  else if (op == '-') *(double*)output = *(const double*)arg1 - *(const double*)arg2;
8542  return;
8543  case ImGuiDataType_COUNT: break;
8544  }
8545  IM_ASSERT(0);
8546 }
8547 
8549 {
8550  size_t Size;
8551  const char* PrintFmt; // Unused
8552  const char* ScanFmt;
8553 };
8554 
8555 static const ImGuiDataTypeInfo GDataTypeInfo[] =
8556 {
8557  { sizeof(int), "%d", "%d" },
8558  { sizeof(unsigned int), "%u", "%u" },
8559 #ifdef _MSC_VER
8560  { sizeof(ImS64), "%I64d","%I64d" },
8561  { sizeof(ImU64), "%I64u","%I64u" },
8562 #else
8563  { sizeof(ImS64), "%lld", "%lld" },
8564  { sizeof(ImU64), "%llu", "%llu" },
8565 #endif
8566  { sizeof(float), "%f", "%f" }, // float are promoted to double in va_arg
8567  { sizeof(double), "%f", "%lf" },
8568 };
8570 
8571 // User can input math operators (e.g. +100) to edit a numerical values.
8572 // NB: This is _not_ a full expression evaluator. We should probably add one and replace this dumb mess..
8573 static bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* data_ptr, const char* format)
8574 {
8575  while (ImCharIsBlankA(*buf))
8576  buf++;
8577 
8578  // We don't support '-' op because it would conflict with inputing negative value.
8579  // Instead you can use +-100 to subtract from an existing value
8580  char op = buf[0];
8581  if (op == '+' || op == '*' || op == '/')
8582  {
8583  buf++;
8584  while (ImCharIsBlankA(*buf))
8585  buf++;
8586  }
8587  else
8588  {
8589  op = 0;
8590  }
8591  if (!buf[0])
8592  return false;
8593 
8594  // Copy the value in an opaque buffer so we can compare at the end of the function if it changed at all.
8595  IM_ASSERT(data_type < ImGuiDataType_COUNT);
8596  int data_backup[2];
8597  IM_ASSERT(GDataTypeInfo[data_type].Size <= sizeof(data_backup));
8598  memcpy(data_backup, data_ptr, GDataTypeInfo[data_type].Size);
8599 
8600  if (format == NULL)
8601  format = GDataTypeInfo[data_type].ScanFmt;
8602 
8603  int arg1i = 0;
8604  if (data_type == ImGuiDataType_S32)
8605  {
8606  int* v = (int*)data_ptr;
8607  int arg0i = *v;
8608  float arg1f = 0.0f;
8609  if (op && sscanf(initial_value_buf, format, &arg0i) < 1)
8610  return false;
8611  // Store operand in a float so we can use fractional value for multipliers (*1.1), but constant always parsed as integer so we can fit big integers (e.g. 2000000003) past float precision
8612  if (op == '+') { if (sscanf(buf, "%d", &arg1i)) *v = (int)(arg0i + arg1i); } // Add (use "+-" to subtract)
8613  else if (op == '*') { if (sscanf(buf, "%f", &arg1f)) *v = (int)(arg0i * arg1f); } // Multiply
8614  else if (op == '/') { if (sscanf(buf, "%f", &arg1f) && arg1f != 0.0f) *v = (int)(arg0i / arg1f); } // Divide
8615  else { if (sscanf(buf, format, &arg1i) == 1) *v = arg1i; } // Assign constant
8616  }
8617  else if (data_type == ImGuiDataType_U32 || data_type == ImGuiDataType_S64 || data_type == ImGuiDataType_U64)
8618  {
8619  // Assign constant
8620  // FIXME: We don't bother handling support for legacy operators since they are a little too crappy. Instead we may implement a proper expression evaluator in the future.
8621  sscanf(buf, format, data_ptr);
8622  }
8623  else if (data_type == ImGuiDataType_Float)
8624  {
8625  // For floats we have to ignore format with precision (e.g. "%.2f") because sscanf doesn't take them in
8626  format = "%f";
8627  float* v = (float*)data_ptr;
8628  float arg0f = *v, arg1f = 0.0f;
8629  if (op && sscanf(initial_value_buf, format, &arg0f) < 1)
8630  return false;
8631  if (sscanf(buf, format, &arg1f) < 1)
8632  return false;
8633  if (op == '+') { *v = arg0f + arg1f; } // Add (use "+-" to subtract)
8634  else if (op == '*') { *v = arg0f * arg1f; } // Multiply
8635  else if (op == '/') { if (arg1f != 0.0f) *v = arg0f / arg1f; } // Divide
8636  else { *v = arg1f; } // Assign constant
8637  }
8638  else if (data_type == ImGuiDataType_Double)
8639  {
8640  format = "%lf"; // scanf differentiate float/double unlike printf which forces everything to double because of ellipsis
8641  double* v = (double*)data_ptr;
8642  double arg0f = *v, arg1f = 0.0;
8643  if (op && sscanf(initial_value_buf, format, &arg0f) < 1)
8644  return false;
8645  if (sscanf(buf, format, &arg1f) < 1)
8646  return false;
8647  if (op == '+') { *v = arg0f + arg1f; } // Add (use "+-" to subtract)
8648  else if (op == '*') { *v = arg0f * arg1f; } // Multiply
8649  else if (op == '/') { if (arg1f != 0.0f) *v = arg0f / arg1f; } // Divide
8650  else { *v = arg1f; } // Assign constant
8651  }
8652  return memcmp(data_backup, data_ptr, GDataTypeInfo[data_type].Size) != 0;
8653 }
8654 
8655 // Create text input in place of a slider (when CTRL+Clicking on slider)
8656 // FIXME: Logic is messy and confusing.
8657 bool ImGui::InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* data_ptr, const char* format)
8658 {
8659  ImGuiContext& g = *GImGui;
8660  ImGuiWindow* window = GetCurrentWindow();
8661 
8662  // Our replacement widget will override the focus ID (registered previously to allow for a TAB focus to happen)
8663  // On the first frame, g.ScalarAsInputTextId == 0, then on subsequent frames it becomes == id
8664  SetActiveID(g.ScalarAsInputTextId, window);
8666  SetHoveredID(0);
8667  FocusableItemUnregister(window);
8668 
8669  char fmt_buf[32];
8670  char data_buf[32];
8671  format = ImParseFormatTrimDecorations(format, fmt_buf, IM_ARRAYSIZE(fmt_buf));
8672  DataTypeFormatString(data_buf, IM_ARRAYSIZE(data_buf), data_type, data_ptr, format);
8673  ImStrTrimBlanks(data_buf);
8675  bool value_changed = InputTextEx(label, data_buf, IM_ARRAYSIZE(data_buf), bb.GetSize(), flags);
8676  if (g.ScalarAsInputTextId == 0) // First frame we started displaying the InputText widget
8677  {
8678  IM_ASSERT(g.ActiveId == id); // InputText ID expected to match the Slider ID
8680  SetHoveredID(id);
8681  }
8682  if (value_changed)
8683  return DataTypeApplyOpFromText(data_buf, g.InputTextState.InitialText.begin(), data_type, data_ptr, NULL);
8684  return false;
8685 }
8686 
8687 // We don't use strchr() because our strings are usually very short and often start with '%'
8688 const char* ImParseFormatFindStart(const char* fmt)
8689 {
8690  while (char c = fmt[0])
8691  {
8692  if (c == '%' && fmt[1] != '%')
8693  return fmt;
8694  else if (c == '%')
8695  fmt++;
8696  fmt++;
8697  }
8698  return fmt;
8699 }
8700 
8701 const char* ImParseFormatFindEnd(const char* fmt)
8702 {
8703  // Printf/scanf types modifiers: I/L/h/j/l/t/w/z. Other uppercase letters qualify as types aka end of the format.
8704  if (fmt[0] != '%')
8705  return fmt;
8706  const unsigned int ignored_uppercase_mask = (1 << ('I'-'A')) | (1 << ('L'-'A'));
8707  const unsigned int ignored_lowercase_mask = (1 << ('h'-'a')) | (1 << ('j'-'a')) | (1 << ('l'-'a')) | (1 << ('t'-'a')) | (1 << ('w'-'a')) | (1 << ('z'-'a'));
8708  for (char c; (c = *fmt) != 0; fmt++)
8709  {
8710  if (c >= 'A' && c <= 'Z' && ((1 << (c - 'A')) & ignored_uppercase_mask) == 0)
8711  return fmt + 1;
8712  if (c >= 'a' && c <= 'z' && ((1 << (c - 'a')) & ignored_lowercase_mask) == 0)
8713  return fmt + 1;
8714  }
8715  return fmt;
8716 }
8717 
8718 // Extract the format out of a format string with leading or trailing decorations
8719 // fmt = "blah blah" -> return fmt
8720 // fmt = "%.3f" -> return fmt
8721 // fmt = "hello %.3f" -> return fmt + 6
8722 // fmt = "%.3f hello" -> return buf written with "%.3f"
8723 const char* ImParseFormatTrimDecorations(const char* fmt, char* buf, int buf_size)
8724 {
8725  const char* fmt_start = ImParseFormatFindStart(fmt);
8726  if (fmt_start[0] != '%')
8727  return fmt;
8728  const char* fmt_end = ImParseFormatFindEnd(fmt_start);
8729  if (fmt_end[0] == 0) // If we only have leading decoration, we don't need to copy the data.
8730  return fmt_start;
8731  ImStrncpy(buf, fmt_start, ImMin((int)(fmt_end + 1 - fmt_start), buf_size));
8732  return buf;
8733 }
8734 
8735 // Parse display precision back from the display format string
8736 // FIXME: This is still used by some navigation code path to infer a minimum tweak step, but we should aim to rework widgets so it isn't needed.
8737 int ImParseFormatPrecision(const char* fmt, int default_precision)
8738 {
8739  fmt = ImParseFormatFindStart(fmt);
8740  if (fmt[0] != '%')
8741  return default_precision;
8742  fmt++;
8743  while (*fmt >= '0' && *fmt <= '9')
8744  fmt++;
8745  int precision = INT_MAX;
8746  if (*fmt == '.')
8747  {
8748  fmt = ImAtoi<int>(fmt + 1, &precision);
8750  precision = default_precision;
8751  }
8752  if (*fmt == 'e' || *fmt == 'E') // Maximum precision with scientific notation
8753  precision = -1;
8754  if ((*fmt == 'g' || *fmt == 'G') && precision == INT_MAX)
8755  precision = -1;
8756  return (precision == INT_MAX) ? default_precision : precision;
8757 }
8758 
8759 static float GetMinimumStepAtDecimalPrecision(int decimal_precision)
8760 {
8761  static const float min_steps[10] = { 1.0f, 0.1f, 0.01f, 0.001f, 0.0001f, 0.00001f, 0.000001f, 0.0000001f, 0.00000001f, 0.000000001f };
8762  if (decimal_precision < 0)
8763  return FLT_MIN;
8764  return (decimal_precision >= 0 && decimal_precision < 10) ? min_steps[decimal_precision] : ImPow(10.0f, (float)-decimal_precision);
8765 }
8766 
8767 template<typename TYPE, typename SIGNEDTYPE>
8768 static inline TYPE RoundScalarWithFormat(const char* format, ImGuiDataType data_type, TYPE v)
8769 {
8770  const char* fmt_start = ImParseFormatFindStart(format);
8771  if (fmt_start[0] != '%' || fmt_start[1] == '%') // Don't apply if the value is not visible in the format string
8772  return v;
8773  char v_str[64];
8774  ImFormatString(v_str, IM_ARRAYSIZE(v_str), fmt_start, v);
8775  const char* p = v_str;
8776  while (*p == ' ')
8777  p++;
8778  if (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double)
8779  v = (TYPE)ImAtof(p);
8780  else
8781  ImAtoi(p, (SIGNEDTYPE*)&v);
8782  return v;
8783 }
8784 
8785 template<typename TYPE, typename FLOATTYPE>
8786 static inline float SliderBehaviorCalcRatioFromValue(ImGuiDataType data_type, TYPE v, TYPE v_min, TYPE v_max, float power, float linear_zero_pos)
8787 {
8788  if (v_min == v_max)
8789  return 0.0f;
8790 
8791  const bool is_power = (power != 1.0f) && (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double);
8792  const TYPE v_clamped = (v_min < v_max) ? ImClamp(v, v_min, v_max) : ImClamp(v, v_max, v_min);
8793  if (is_power)
8794  {
8795  if (v_clamped < 0.0f)
8796  {
8797  const float f = 1.0f - (float)((v_clamped - v_min) / (ImMin((TYPE)0, v_max) - v_min));
8798  return (1.0f - ImPow(f, 1.0f/power)) * linear_zero_pos;
8799  }
8800  else
8801  {
8802  const float f = (float)((v_clamped - ImMax((TYPE)0, v_min)) / (v_max - ImMax((TYPE)0, v_min)));
8803  return linear_zero_pos + ImPow(f, 1.0f/power) * (1.0f - linear_zero_pos);
8804  }
8805  }
8806 
8807  // Linear slider
8808  return (float)((FLOATTYPE)(v_clamped - v_min) / (FLOATTYPE)(v_max - v_min));
8809 }
8810 
8811 // FIXME: Move some of the code into SliderBehavior(). Current responsability is larger than what the equivalent DragBehaviorT<> does, we also do some rendering, etc.
8812 template<typename TYPE, typename SIGNEDTYPE, typename FLOATTYPE>
8813 static bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, TYPE* v, const TYPE v_min, const TYPE v_max, const char* format, float power, ImGuiSliderFlags flags)
8814 {
8815  ImGuiContext& g = *GImGui;
8816  ImGuiWindow* window = GetCurrentWindow();
8817  const ImGuiStyle& style = g.Style;
8818 
8819  // Draw frame
8821  RenderNavHighlight(bb, id);
8822  RenderFrame(bb.Min, bb.Max, frame_col, true, style.FrameRounding);
8823 
8824  const bool is_horizontal = (flags & ImGuiSliderFlags_Vertical) == 0;
8825  const bool is_decimal = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double);
8826  const bool is_power = (power != 1.0f) && is_decimal;
8827 
8828  const float grab_padding = 2.0f;
8829  const float slider_sz = is_horizontal ? (bb.GetWidth() - grab_padding * 2.0f) : (bb.GetHeight() - grab_padding * 2.0f);
8830  float grab_sz = style.GrabMinSize;
8831  SIGNEDTYPE v_range = (v_min < v_max ? v_max - v_min : v_min - v_max);
8832  if (!is_decimal && v_range >= 0) // v_range < 0 may happen on integer overflows
8833  grab_sz = ImMax((float)(slider_sz / (v_range + 1)), style.GrabMinSize); // For integer sliders: if possible have the grab size represent 1 unit
8834  grab_sz = ImMin(grab_sz, slider_sz);
8835  const float slider_usable_sz = slider_sz - grab_sz;
8836  const float slider_usable_pos_min = (is_horizontal ? bb.Min.x : bb.Min.y) + grab_padding + grab_sz*0.5f;
8837  const float slider_usable_pos_max = (is_horizontal ? bb.Max.x : bb.Max.y) - grab_padding - grab_sz*0.5f;
8838 
8839  // For power curve sliders that cross over sign boundary we want the curve to be symmetric around 0.0f
8840  float linear_zero_pos; // 0.0->1.0f
8841  if (is_power && v_min * v_max < 0.0f)
8842  {
8843  // Different sign
8844  const FLOATTYPE linear_dist_min_to_0 = ImPow(v_min >= 0 ? (FLOATTYPE)v_min : -(FLOATTYPE)v_min, (FLOATTYPE)1.0f/power);
8845  const FLOATTYPE linear_dist_max_to_0 = ImPow(v_max >= 0 ? (FLOATTYPE)v_max : -(FLOATTYPE)v_max, (FLOATTYPE)1.0f/power);
8846  linear_zero_pos = (float)(linear_dist_min_to_0 / (linear_dist_min_to_0 + linear_dist_max_to_0));
8847  }
8848  else
8849  {
8850  // Same sign
8851  linear_zero_pos = v_min < 0.0f ? 1.0f : 0.0f;
8852  }
8853 
8854  // Process interacting with the slider
8855  bool value_changed = false;
8856  if (g.ActiveId == id)
8857  {
8858  bool set_new_value = false;
8859  float clicked_t = 0.0f;
8861  {
8862  if (!g.IO.MouseDown[0])
8863  {
8864  ClearActiveID();
8865  }
8866  else
8867  {
8868  const float mouse_abs_pos = is_horizontal ? g.IO.MousePos.x : g.IO.MousePos.y;
8869  clicked_t = (slider_usable_sz > 0.0f) ? ImClamp((mouse_abs_pos - slider_usable_pos_min) / slider_usable_sz, 0.0f, 1.0f) : 0.0f;
8870  if (!is_horizontal)
8871  clicked_t = 1.0f - clicked_t;
8872  set_new_value = true;
8873  }
8874  }
8875  else if (g.ActiveIdSource == ImGuiInputSource_Nav)
8876  {
8878  float delta = is_horizontal ? delta2.x : -delta2.y;
8880  {
8881  ClearActiveID();
8882  }
8883  else if (delta != 0.0f)
8884  {
8885  clicked_t = SliderBehaviorCalcRatioFromValue<TYPE,FLOATTYPE>(data_type, *v, v_min, v_max, power, linear_zero_pos);
8886  if (is_decimal || is_power)
8887  {
8888  delta /= 100.0f; // Gamepad/keyboard tweak speeds in % of slider bounds
8889  if (IsNavInputDown(ImGuiNavInput_TweakSlow))
8890  delta /= 10.0f;
8891  }
8892  else
8893  {
8894  if ((v_range >= -100.0f && v_range <= 100.0f) || IsNavInputDown(ImGuiNavInput_TweakSlow))
8895  delta = ((delta < 0.0f) ? -1.0f : +1.0f) / (float)v_range; // Gamepad/keyboard tweak speeds in integer steps
8896  else
8897  delta /= 100.0f;
8898  }
8899  if (IsNavInputDown(ImGuiNavInput_TweakFast))
8900  delta *= 10.0f;
8901  set_new_value = true;
8902  if ((clicked_t >= 1.0f && delta > 0.0f) || (clicked_t <= 0.0f && delta < 0.0f)) // This is to avoid applying the saturation when already past the limits
8903  set_new_value = false;
8904  else
8905  clicked_t = ImSaturate(clicked_t + delta);
8906  }
8907  }
8908 
8909  if (set_new_value)
8910  {
8911  TYPE v_new;
8912  if (is_power)
8913  {
8914  // Account for power curve scale on both sides of the zero
8915  if (clicked_t < linear_zero_pos)
8916  {
8917  // Negative: rescale to the negative range before powering
8918  float a = 1.0f - (clicked_t / linear_zero_pos);
8919  a = ImPow(a, power);
8920  v_new = ImLerp(ImMin(v_max, (TYPE)0), v_min, a);
8921  }
8922  else
8923  {
8924  // Positive: rescale to the positive range before powering
8925  float a;
8926  if (ImFabs(linear_zero_pos - 1.0f) > 1.e-6f)
8927  a = (clicked_t - linear_zero_pos) / (1.0f - linear_zero_pos);
8928  else
8929  a = clicked_t;
8930  a = ImPow(a, power);
8931  v_new = ImLerp(ImMax(v_min, (TYPE)0), v_max, a);
8932  }
8933  }
8934  else
8935  {
8936  // Linear slider
8937  if (is_decimal)
8938  {
8939  v_new = ImLerp(v_min, v_max, clicked_t);
8940  }
8941  else
8942  {
8943  // For integer values we want the clicking position to match the grab box so we round above
8944  // This code is carefully tuned to work with large values (e.g. high ranges of U64) while preserving this property..
8945  FLOATTYPE v_new_off_f = (v_max - v_min) * clicked_t;
8946  TYPE v_new_off_floor = (TYPE)(v_new_off_f);
8947  TYPE v_new_off_round = (TYPE)(v_new_off_f + (FLOATTYPE)0.5);
8948  if (!is_decimal && v_new_off_floor < v_new_off_round)
8949  v_new = v_min + v_new_off_round;
8950  else
8951  v_new = v_min + v_new_off_floor;
8952  }
8953  }
8954 
8955  // Round to user desired precision based on format string
8956  v_new = RoundScalarWithFormat<TYPE,SIGNEDTYPE>(format, data_type, v_new);
8957 
8958  // Apply result
8959  if (*v != v_new)
8960  {
8961  *v = v_new;
8962  value_changed = true;
8963  }
8964  }
8965  }
8966 
8967  // Draw
8968  float grab_t = SliderBehaviorCalcRatioFromValue<TYPE,FLOATTYPE>(data_type, *v, v_min, v_max, power, linear_zero_pos);
8969  if (!is_horizontal)
8970  grab_t = 1.0f - grab_t;
8971  const float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t);
8972  ImRect grab_bb;
8973  if (is_horizontal)
8974  grab_bb = ImRect(grab_pos - grab_sz*0.5f, bb.Min.y + grab_padding, grab_pos + grab_sz*0.5f, bb.Max.y - grab_padding);
8975  else
8976  grab_bb = ImRect(bb.Min.x + grab_padding, grab_pos - grab_sz*0.5f, bb.Max.x - grab_padding, grab_pos + grab_sz*0.5f);
8978 
8979  return value_changed;
8980 }
8981 
8982 // For 32-bits and larger types, slider bounds are limited to half the natural type range.
8983 // So e.g. an integer Slider between INT_MAX-10 and INT_MAX will fail, but an integer Slider between INT_MAX/2-10 and INT_MAX/2.
8984 // It would be possible to life that limitation with some work but it doesn't seem to be work it for sliders.
8985 bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format, float power, ImGuiSliderFlags flags)
8986 {
8987  switch (data_type)
8988  {
8989  case ImGuiDataType_S32:
8990  IM_ASSERT(*(const ImS32*)v_min >= IM_S32_MIN/2 && *(const ImS32*)v_max <= IM_S32_MAX/2);
8991  return SliderBehaviorT<ImS32, ImS32, float >(bb, id, data_type, (ImS32*)v, *(const ImS32*)v_min, *(const ImS32*)v_max, format, power, flags);
8992  case ImGuiDataType_U32:
8993  IM_ASSERT(*(const ImU32*)v_min <= IM_U32_MAX/2);
8994  return SliderBehaviorT<ImU32, ImS32, float >(bb, id, data_type, (ImU32*)v, *(const ImU32*)v_min, *(const ImU32*)v_max, format, power, flags);
8995  case ImGuiDataType_S64:
8996  IM_ASSERT(*(const ImS64*)v_min >= IM_S64_MIN/2 && *(const ImS64*)v_max <= IM_S64_MAX/2);
8997  return SliderBehaviorT<ImS64, ImS64, double>(bb, id, data_type, (ImS64*)v, *(const ImS64*)v_min, *(const ImS64*)v_max, format, power, flags);
8998  case ImGuiDataType_U64:
8999  IM_ASSERT(*(const ImU64*)v_min <= IM_U64_MAX/2);
9000  return SliderBehaviorT<ImU64, ImS64, double>(bb, id, data_type, (ImU64*)v, *(const ImU64*)v_min, *(const ImU64*)v_max, format, power, flags);
9001  case ImGuiDataType_Float:
9002  IM_ASSERT(*(const float*)v_min >= -FLT_MAX/2.0f && *(const float*)v_max <= FLT_MAX/2.0f);
9003  return SliderBehaviorT<float, float, float >(bb, id, data_type, (float*)v, *(const float*)v_min, *(const float*)v_max, format, power, flags);
9004  case ImGuiDataType_Double:
9005  IM_ASSERT(*(const double*)v_min >= -DBL_MAX/2.0f && *(const double*)v_max <= DBL_MAX/2.0f);
9006  return SliderBehaviorT<double,double,double>(bb, id, data_type, (double*)v, *(const double*)v_min, *(const double*)v_max, format, power, flags);
9007  case ImGuiDataType_COUNT: break;
9008  }
9009  IM_ASSERT(0);
9010  return false;
9011 }
9012 
9013 // FIXME-LEGACY: Prior to 1.61 our DragInt() function internally used floats and because of this the compile-time default value for format was "%.0f".
9014 // Even though we changed the compile-time default, we expect users to have carried %f around, which would break the display of DragInt() calls.
9015 // To honor backward compatibility we are rewriting the format string, unless IMGUI_DISABLE_OBSOLETE_FUNCTIONS is enabled. What could possibly go wrong?!
9016 static const char* PatchFormatStringFloatToInt(const char* fmt)
9017 {
9018  if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '0' && fmt[3] == 'f' && fmt[4] == 0) // Fast legacy path for "%.0f" which is expected to be the most common case.
9019  return "%d";
9020  const char* fmt_start = ImParseFormatFindStart(fmt); // Find % (if any, and ignore %%)
9021  const char* fmt_end = ImParseFormatFindEnd(fmt_start); // Find end of format specifier, which itself is an exercise of confidence/recklessness (because snprintf is dependent on libc or user).
9022  if (fmt_end > fmt_start && fmt_end[-1] == 'f')
9023  {
9024 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
9025  if (fmt_start == fmt && fmt_end[0] == 0)
9026  return "%d";
9027  ImGuiContext& g = *GImGui;
9028  ImFormatString(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), "%.*s%%d%s", (int)(fmt_start - fmt), fmt, fmt_end); // Honor leading and trailing decorations, but lose alignment/precision.
9029  return g.TempBuffer;
9030 #else
9031  IM_ASSERT(0 && "DragInt(): Invalid format string!"); // Old versions used a default parameter of "%.0f", please replace with e.g. "%d"
9032 #endif
9033  }
9034  return fmt;
9035 }
9036 
9037 bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format, float power)
9038 {
9039  ImGuiWindow* window = GetCurrentWindow();
9040  if (window->SkipItems)
9041  return false;
9042 
9043  ImGuiContext& g = *GImGui;
9044  const ImGuiStyle& style = g.Style;
9045  const ImGuiID id = window->GetID(label);
9046  const float w = CalcItemWidth();
9047 
9048  const ImVec2 label_size = CalcTextSize(label, NULL, true);
9049  const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f));
9050  const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
9051 
9052  // NB- we don't call ItemSize() yet because we may turn into a text edit box below
9053  if (!ItemAdd(total_bb, id, &frame_bb))
9054  {
9055  ItemSize(total_bb, style.FramePadding.y);
9056  return false;
9057  }
9058 
9059  // Default format string when passing NULL
9060  // Patch old "%.0f" format string to use "%d", read function comments for more details.
9061  IM_ASSERT(data_type >= 0 && data_type < ImGuiDataType_COUNT);
9062  if (format == NULL)
9063  format = GDataTypeInfo[data_type].PrintFmt;
9064  else if (data_type == ImGuiDataType_S32 && strcmp(format, "%d") != 0)
9065  format = PatchFormatStringFloatToInt(format);
9066 
9067  // Tabbing or CTRL-clicking on Slider turns it into an input box
9068  bool start_text_input = false;
9069  const bool tab_focus_requested = FocusableItemRegister(window, id);
9070  const bool hovered = ItemHoverable(frame_bb, id);
9071  if (tab_focus_requested || (hovered && g.IO.MouseClicked[0]) || g.NavActivateId == id || (g.NavInputId == id && g.ScalarAsInputTextId != id))
9072  {
9073  SetActiveID(id, window);
9074  SetFocusID(id, window);
9075  FocusWindow(window);
9077  if (tab_focus_requested || g.IO.KeyCtrl || g.NavInputId == id)
9078  {
9079  start_text_input = true;
9080  g.ScalarAsInputTextId = 0;
9081  }
9082  }
9083  if (start_text_input || (g.ActiveId == id && g.ScalarAsInputTextId == id))
9084  return InputScalarAsWidgetReplacement(frame_bb, id, label, data_type, v, format);
9085 
9086  // Actual slider behavior + render grab
9087  ItemSize(total_bb, style.FramePadding.y);
9088  const bool value_changed = SliderBehavior(frame_bb, id, data_type, v, v_min, v_max, format, power);
9089 
9090  // Display value using user-provided display format so user can add prefix/suffix/decorations to the value.
9091  char value_buf[64];
9092  const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, v, format);
9093  RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f,0.5f));
9094 
9095  if (label_size.x > 0.0f)
9096  RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
9097 
9098  return value_changed;
9099 }
9100 
9101 bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format, float power)
9102 {
9103  return SliderScalar(label, ImGuiDataType_Float, v, &v_min, &v_max, format, power);
9104 }
9105 
9106 bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format, float power)
9107 {
9108  ImGuiWindow* window = GetCurrentWindow();
9109  if (window->SkipItems)
9110  return false;
9111 
9112  ImGuiContext& g = *GImGui;
9113  const ImGuiStyle& style = g.Style;
9114  const ImGuiID id = window->GetID(label);
9115 
9116  const ImVec2 label_size = CalcTextSize(label, NULL, true);
9117  const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size);
9118  const ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
9119 
9120  ItemSize(bb, style.FramePadding.y);
9121  if (!ItemAdd(frame_bb, id))
9122  return false;
9123 
9124  // Default format string when passing NULL
9125  // Patch old "%.0f" format string to use "%d", read function comments for more details.
9126  IM_ASSERT(data_type >= 0 && data_type < ImGuiDataType_COUNT);
9127  if (format == NULL)
9128  format = GDataTypeInfo[data_type].PrintFmt;
9129  else if (data_type == ImGuiDataType_S32 && strcmp(format, "%d") != 0)
9130  format = PatchFormatStringFloatToInt(format);
9131 
9132  const bool hovered = ItemHoverable(frame_bb, id);
9133  if ((hovered && g.IO.MouseClicked[0]) || g.NavActivateId == id || g.NavInputId == id)
9134  {
9135  SetActiveID(id, window);
9136  SetFocusID(id, window);
9137  FocusWindow(window);
9139  }
9140 
9141  // Actual slider behavior + render grab
9142  bool value_changed = SliderBehavior(frame_bb, id, data_type, v, v_min, v_max, format, power, ImGuiSliderFlags_Vertical);
9143 
9144  // Display value using user-provided display format so user can add prefix/suffix/decorations to the value.
9145  // For the vertical slider we allow centered text to overlap the frame padding
9146  char value_buf[64];
9147  const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, v, format);
9148  RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f,0.0f));
9149  if (label_size.x > 0.0f)
9150  RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
9151 
9152  return value_changed;
9153 }
9154 
9155 bool ImGui::SliderAngle(const char* label, float* v_rad, float v_degrees_min, float v_degrees_max)
9156 {
9157  float v_deg = (*v_rad) * 360.0f / (2*IM_PI);
9158  bool value_changed = SliderFloat(label, &v_deg, v_degrees_min, v_degrees_max, "%.0f deg", 1.0f);
9159  *v_rad = v_deg * (2*IM_PI) / 360.0f;
9160  return value_changed;
9161 }
9162 
9163 bool ImGui::SliderInt(const char* label, int* v, int v_min, int v_max, const char* format)
9164 {
9165  return SliderScalar(label, ImGuiDataType_S32, v, &v_min, &v_max, format);
9166 }
9167 
9168 bool ImGui::VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* format, float power)
9169 {
9170  return VSliderScalar(label, size, ImGuiDataType_Float, v, &v_min, &v_max, format, power);
9171 }
9172 
9173 bool ImGui::VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* format)
9174 {
9175  return VSliderScalar(label, size, ImGuiDataType_S32, v, &v_min, &v_max, format);
9176 }
9177 
9178 // Add multiple sliders on 1 line for compact edition of multiple components
9179 bool ImGui::SliderScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* v_min, const void* v_max, const char* format, float power)
9180 {
9181  ImGuiWindow* window = GetCurrentWindow();
9182  if (window->SkipItems)
9183  return false;
9184 
9185  ImGuiContext& g = *GImGui;
9186  bool value_changed = false;
9187  BeginGroup();
9188  PushID(label);
9189  PushMultiItemsWidths(components);
9190  size_t type_size = GDataTypeInfo[data_type].Size;
9191  for (int i = 0; i < components; i++)
9192  {
9193  PushID(i);
9194  value_changed |= SliderScalar("##v", data_type, v, v_min, v_max, format, power);
9196  PopID();
9197  PopItemWidth();
9198  v = (void*)((char*)v + type_size);
9199  }
9200  PopID();
9201 
9202  TextUnformatted(label, FindRenderedTextEnd(label));
9203  EndGroup();
9204  return value_changed;
9205 }
9206 
9207 bool ImGui::SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format, float power)
9208 {
9209  return SliderScalarN(label, ImGuiDataType_Float, v, 2, &v_min, &v_max, format, power);
9210 }
9211 
9212 bool ImGui::SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format, float power)
9213 {
9214  return SliderScalarN(label, ImGuiDataType_Float, v, 3, &v_min, &v_max, format, power);
9215 }
9216 
9217 bool ImGui::SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format, float power)
9218 {
9219  return SliderScalarN(label, ImGuiDataType_Float, v, 4, &v_min, &v_max, format, power);
9220 }
9221 
9222 bool ImGui::SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* format)
9223 {
9224  return SliderScalarN(label, ImGuiDataType_S32, v, 2, &v_min, &v_max, format);
9225 }
9226 
9227 bool ImGui::SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* format)
9228 {
9229  return SliderScalarN(label, ImGuiDataType_S32, v, 3, &v_min, &v_max, format);
9230 }
9231 
9232 bool ImGui::SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* format)
9233 {
9234  return SliderScalarN(label, ImGuiDataType_S32, v, 4, &v_min, &v_max, format);
9235 }
9236 
9237 // This is called by DragBehavior() when the widget is active (held by mouse or being manipulated with Nav controls)
9238 template<typename TYPE, typename SIGNEDTYPE, typename FLOATTYPE>
9239 static bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const TYPE v_min, const TYPE v_max, const char* format, float power)
9240 {
9241  ImGuiContext& g = *GImGui;
9242 
9243  // Default tweak speed
9244  bool has_min_max = (v_min != v_max) && (v_max - v_max < FLT_MAX);
9245  if (v_speed == 0.0f && has_min_max)
9246  v_speed = (float)((v_max - v_min) * g.DragSpeedDefaultRatio);
9247 
9248  // Inputs accumulates into g.DragCurrentAccum, which is flushed into the current value as soon as it makes a difference with our precision settings
9249  float adjust_delta = 0.0f;
9251  {
9252  adjust_delta = g.IO.MouseDelta.x;
9253  if (g.IO.KeyAlt)
9254  adjust_delta *= 1.0f/100.0f;
9255  if (g.IO.KeyShift)
9256  adjust_delta *= 10.0f;
9257  }
9259  {
9260  int decimal_precision = (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) ? ImParseFormatPrecision(format, 3) : 0;
9262  v_speed = ImMax(v_speed, GetMinimumStepAtDecimalPrecision(decimal_precision));
9263  }
9264  adjust_delta *= v_speed;
9265 
9266  // Clear current value on activation
9267  // Avoid altering values and clamping when we are _already_ past the limits and heading in the same direction, so e.g. if range is 0..255, current value is 300 and we are pushing to the right side, keep the 300.
9268  bool is_just_activated = g.ActiveIdIsJustActivated;
9269  bool is_already_past_limits_and_pushing_outward = has_min_max && ((*v >= v_max && adjust_delta > 0.0f) || (*v <= v_min && adjust_delta < 0.0f));
9270  if (is_just_activated || is_already_past_limits_and_pushing_outward)
9271  {
9272  g.DragCurrentAccum = 0.0f;
9273  g.DragCurrentAccumDirty = false;
9274  }
9275  else if (adjust_delta != 0.0f)
9276  {
9277  g.DragCurrentAccum += adjust_delta;
9278  g.DragCurrentAccumDirty = true;
9279  }
9280 
9281  if (!g.DragCurrentAccumDirty)
9282  return false;
9283 
9284  TYPE v_cur = *v;
9285  FLOATTYPE v_old_ref_for_accum_remainder = (FLOATTYPE)0.0f;
9286 
9287  const bool is_power = (power != 1.0f && (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) && has_min_max);
9288  if (is_power)
9289  {
9290  // Offset + round to user desired precision, with a curve on the v_min..v_max range to get more precision on one side of the range
9291  FLOATTYPE v_old_norm_curved = ImPow((FLOATTYPE)(v_cur - v_min) / (FLOATTYPE)(v_max - v_min), (FLOATTYPE)1.0f / power);
9292  FLOATTYPE v_new_norm_curved = v_old_norm_curved + (g.DragCurrentAccum / (v_max - v_min));
9293  v_cur = v_min + (TYPE)ImPow(ImSaturate((float)v_new_norm_curved), power) * (v_max - v_min);
9294  v_old_ref_for_accum_remainder = v_old_norm_curved;
9295  }
9296  else
9297  {
9298  v_cur += (TYPE)g.DragCurrentAccum;
9299  }
9300 
9301  // Round to user desired precision based on format string
9302  v_cur = RoundScalarWithFormat<TYPE, SIGNEDTYPE>(format, data_type, v_cur);
9303 
9304  // Preserve remainder after rounding has been applied. This also allow slow tweaking of values.
9305  g.DragCurrentAccumDirty = false;
9306  if (is_power)
9307  {
9308  FLOATTYPE v_cur_norm_curved = ImPow((FLOATTYPE)(v_cur - v_min) / (FLOATTYPE)(v_max - v_min), (FLOATTYPE)1.0f / power);
9309  g.DragCurrentAccum -= (float)(v_cur_norm_curved - v_old_ref_for_accum_remainder);
9310  }
9311  else
9312  {
9313  g.DragCurrentAccum -= (float)((SIGNEDTYPE)v_cur - (SIGNEDTYPE)*v);
9314  }
9315 
9316  // Lose zero sign for float/double
9317  if (v_cur == (TYPE)-0)
9318  v_cur = (TYPE)0;
9319 
9320  // Clamp values (handle overflow/wrap-around)
9321  if (*v != v_cur && has_min_max)
9322  {
9323  if (v_cur < v_min || (v_cur > *v && adjust_delta < 0.0f))
9324  v_cur = v_min;
9325  if (v_cur > v_max || (v_cur < *v && adjust_delta > 0.0f))
9326  v_cur = v_max;
9327  }
9328 
9329  // Apply result
9330  if (*v == v_cur)
9331  return false;
9332  *v = v_cur;
9333  return true;
9334 }
9335 
9336 bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* v, float v_speed, const void* v_min, const void* v_max, const char* format, float power)
9337 {
9338  ImGuiContext& g = *GImGui;
9339  if (g.ActiveId == id)
9340  {
9342  ClearActiveID();
9344  ClearActiveID();
9345  }
9346  if (g.ActiveId != id)
9347  return false;
9348 
9349  switch (data_type)
9350  {
9351  case ImGuiDataType_S32: return DragBehaviorT<ImS32, ImS32, float >(data_type, (ImS32*)v, v_speed, v_min ? *(const ImS32* )v_min : IM_S32_MIN, v_max ? *(const ImS32* )v_max : IM_S32_MAX, format, power);
9352  case ImGuiDataType_U32: return DragBehaviorT<ImU32, ImS32, float >(data_type, (ImU32*)v, v_speed, v_min ? *(const ImU32* )v_min : IM_U32_MIN, v_max ? *(const ImU32* )v_max : IM_U32_MAX, format, power);
9353  case ImGuiDataType_S64: return DragBehaviorT<ImS64, ImS64, double>(data_type, (ImS64*)v, v_speed, v_min ? *(const ImS64* )v_min : IM_S64_MIN, v_max ? *(const ImS64* )v_max : IM_S64_MAX, format, power);
9354  case ImGuiDataType_U64: return DragBehaviorT<ImU64, ImS64, double>(data_type, (ImU64*)v, v_speed, v_min ? *(const ImU64* )v_min : IM_U64_MIN, v_max ? *(const ImU64* )v_max : IM_U64_MAX, format, power);
9355  case ImGuiDataType_Float: return DragBehaviorT<float, float, float >(data_type, (float*)v, v_speed, v_min ? *(const float* )v_min : -FLT_MAX, v_max ? *(const float* )v_max : FLT_MAX, format, power);
9356  case ImGuiDataType_Double: return DragBehaviorT<double,double,double>(data_type, (double*)v, v_speed, v_min ? *(const double*)v_min : -DBL_MAX, v_max ? *(const double*)v_max : DBL_MAX, format, power);
9357  case ImGuiDataType_COUNT: break;
9358  }
9359  IM_ASSERT(0);
9360  return false;
9361 }
9362 
9363 bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* v, float v_speed, const void* v_min, const void* v_max, const char* format, float power)
9364 {
9365  ImGuiWindow* window = GetCurrentWindow();
9366  if (window->SkipItems)
9367  return false;
9368 
9369  if (power != 1.0f)
9370  IM_ASSERT(v_min != NULL && v_max != NULL); // When using a power curve the drag needs to have known bounds
9371 
9372  ImGuiContext& g = *GImGui;
9373  const ImGuiStyle& style = g.Style;
9374  const ImGuiID id = window->GetID(label);
9375  const float w = CalcItemWidth();
9376 
9377  const ImVec2 label_size = CalcTextSize(label, NULL, true);
9378  const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f));
9379  const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding);
9380  const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
9381 
9382  // NB- we don't call ItemSize() yet because we may turn into a text edit box below
9383  if (!ItemAdd(total_bb, id, &frame_bb))
9384  {
9385  ItemSize(total_bb, style.FramePadding.y);
9386  return false;
9387  }
9388  const bool hovered = ItemHoverable(frame_bb, id);
9389 
9390  // Default format string when passing NULL
9391  // Patch old "%.0f" format string to use "%d", read function comments for more details.
9392  IM_ASSERT(data_type >= 0 && data_type < ImGuiDataType_COUNT);
9393  if (format == NULL)
9394  format = GDataTypeInfo[data_type].PrintFmt;
9395  else if (data_type == ImGuiDataType_S32 && strcmp(format, "%d") != 0)
9396  format = PatchFormatStringFloatToInt(format);
9397 
9398  // Tabbing or CTRL-clicking on Drag turns it into an input box
9399  bool start_text_input = false;
9400  const bool tab_focus_requested = FocusableItemRegister(window, id);
9401  if (tab_focus_requested || (hovered && (g.IO.MouseClicked[0] || g.IO.MouseDoubleClicked[0])) || g.NavActivateId == id || (g.NavInputId == id && g.ScalarAsInputTextId != id))
9402  {
9403  SetActiveID(id, window);
9404  SetFocusID(id, window);
9405  FocusWindow(window);
9407  if (tab_focus_requested || g.IO.KeyCtrl || g.IO.MouseDoubleClicked[0] || g.NavInputId == id)
9408  {
9409  start_text_input = true;
9410  g.ScalarAsInputTextId = 0;
9411  }
9412  }
9413  if (start_text_input || (g.ActiveId == id && g.ScalarAsInputTextId == id))
9414  return InputScalarAsWidgetReplacement(frame_bb, id, label, data_type, v, format);
9415 
9416  // Actual drag behavior
9417  ItemSize(total_bb, style.FramePadding.y);
9418  const bool value_changed = DragBehavior(id, data_type, v, v_speed, v_min, v_max, format, power);
9419 
9420  // Draw frame
9422  RenderNavHighlight(frame_bb, id);
9423  RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, style.FrameRounding);
9424 
9425  // Display value using user-provided display format so user can add prefix/suffix/decorations to the value.
9426  char value_buf[64];
9427  const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, v, format);
9428  RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f));
9429 
9430  if (label_size.x > 0.0f)
9431  RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label);
9432 
9433  return value_changed;
9434 }
9435 
9436 bool ImGui::DragScalarN(const char* label, ImGuiDataType data_type, void* v, int components, float v_speed, const void* v_min, const void* v_max, const char* format, float power)
9437 {
9438  ImGuiWindow* window = GetCurrentWindow();
9439  if (window->SkipItems)
9440  return false;
9441 
9442  ImGuiContext& g = *GImGui;
9443  bool value_changed = false;
9444  BeginGroup();
9445  PushID(label);
9446  PushMultiItemsWidths(components);
9447  size_t type_size = GDataTypeInfo[data_type].Size;
9448  for (int i = 0; i < components; i++)
9449  {
9450  PushID(i);
9451  value_changed |= DragScalar("##v", data_type, v, v_speed, v_min, v_max, format, power);
9453  PopID();
9454  PopItemWidth();
9455  v = (void*)((char*)v + type_size);
9456  }
9457  PopID();
9458 
9459  TextUnformatted(label, FindRenderedTextEnd(label));
9460  EndGroup();
9461  return value_changed;
9462 }
9463 
9464 bool ImGui::DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max, const char* format, float power)
9465 {
9466  return DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, format, power);
9467 }
9468 
9469 bool ImGui::DragFloat2(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* format, float power)
9470 {
9471  return DragScalarN(label, ImGuiDataType_Float, v, 2, v_speed, &v_min, &v_max, format, power);
9472 }
9473 
9474 bool ImGui::DragFloat3(const char* label, float v[3], float v_speed, float v_min, float v_max, const char* format, float power)
9475 {
9476  return DragScalarN(label, ImGuiDataType_Float, v, 3, v_speed, &v_min, &v_max, format, power);
9477 }
9478 
9479 bool ImGui::DragFloat4(const char* label, float v[4], float v_speed, float v_min, float v_max, const char* format, float power)
9480 {
9481  return DragScalarN(label, ImGuiDataType_Float, v, 4, v_speed, &v_min, &v_max, format, power);
9482 }
9483 
9484 bool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_current_max, float v_speed, float v_min, float v_max, const char* format, const char* format_max, float power)
9485 {
9486  ImGuiWindow* window = GetCurrentWindow();
9487  if (window->SkipItems)
9488  return false;
9489 
9490  ImGuiContext& g = *GImGui;
9491  PushID(label);
9492  BeginGroup();
9494 
9495  bool value_changed = DragFloat("##min", v_current_min, v_speed, (v_min >= v_max) ? -FLT_MAX : v_min, (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max), format, power);
9496  PopItemWidth();
9498  value_changed |= DragFloat("##max", v_current_max, v_speed, (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min), (v_min >= v_max) ? FLT_MAX : v_max, format_max ? format_max : format, power);
9499  PopItemWidth();
9501 
9502  TextUnformatted(label, FindRenderedTextEnd(label));
9503  EndGroup();
9504  PopID();
9505 
9506  return value_changed;
9507 }
9508 
9509 // NB: v_speed is float to allow adjusting the drag speed with more precision
9510 bool ImGui::DragInt(const char* label, int* v, float v_speed, int v_min, int v_max, const char* format)
9511 {
9512  return DragScalar(label, ImGuiDataType_S32, v, v_speed, &v_min, &v_max, format);
9513 }
9514 
9515 bool ImGui::DragInt2(const char* label, int v[2], float v_speed, int v_min, int v_max, const char* format)
9516 {
9517  return DragScalarN(label, ImGuiDataType_S32, v, 2, v_speed, &v_min, &v_max, format);
9518 }
9519 
9520 bool ImGui::DragInt3(const char* label, int v[3], float v_speed, int v_min, int v_max, const char* format)
9521 {
9522  return DragScalarN(label, ImGuiDataType_S32, v, 3, v_speed, &v_min, &v_max, format);
9523 }
9524 
9525 bool ImGui::DragInt4(const char* label, int v[4], float v_speed, int v_min, int v_max, const char* format)
9526 {
9527  return DragScalarN(label, ImGuiDataType_S32, v, 4, v_speed, &v_min, &v_max, format);
9528 }
9529 
9530 bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_max, float v_speed, int v_min, int v_max, const char* format, const char* format_max)
9531 {
9532  ImGuiWindow* window = GetCurrentWindow();
9533  if (window->SkipItems)
9534  return false;
9535 
9536  ImGuiContext& g = *GImGui;
9537  PushID(label);
9538  BeginGroup();
9540 
9541  bool value_changed = DragInt("##min", v_current_min, v_speed, (v_min >= v_max) ? INT_MIN : v_min, (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max), format);
9542  PopItemWidth();
9544  value_changed |= DragInt("##max", v_current_max, v_speed, (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min), (v_min >= v_max) ? INT_MAX : v_max, format_max ? format_max : format);
9545  PopItemWidth();
9547 
9548  TextUnformatted(label, FindRenderedTextEnd(label));
9549  EndGroup();
9550  PopID();
9551 
9552  return value_changed;
9553 }
9554 
9555 void ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size)
9556 {
9557  ImGuiWindow* window = GetCurrentWindow();
9558  if (window->SkipItems)
9559  return;
9560 
9561  ImGuiContext& g = *GImGui;
9562  const ImGuiStyle& style = g.Style;
9563 
9564  const ImVec2 label_size = CalcTextSize(label, NULL, true);
9565  if (graph_size.x == 0.0f)
9566  graph_size.x = CalcItemWidth();
9567  if (graph_size.y == 0.0f)
9568  graph_size.y = label_size.y + (style.FramePadding.y * 2);
9569 
9570  const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(graph_size.x, graph_size.y));
9571  const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding);
9572  const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0));
9573  ItemSize(total_bb, style.FramePadding.y);
9574  if (!ItemAdd(total_bb, 0, &frame_bb))
9575  return;
9576  const bool hovered = ItemHoverable(inner_bb, 0);
9577 
9578  // Determine scale from values if not specified
9579  if (scale_min == FLT_MAX || scale_max == FLT_MAX)
9580  {
9581  float v_min = FLT_MAX;
9582  float v_max = -FLT_MAX;
9583  for (int i = 0; i < values_count; i++)
9584  {
9585  const float v = values_getter(data, i);
9586  v_min = ImMin(v_min, v);
9587  v_max = ImMax(v_max, v);
9588  }
9589  if (scale_min == FLT_MAX)
9590  scale_min = v_min;
9591  if (scale_max == FLT_MAX)
9592  scale_max = v_max;
9593  }
9594 
9595  RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
9596 
9597  if (values_count > 0)
9598  {
9599  int res_w = ImMin((int)graph_size.x, values_count) + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0);
9600  int item_count = values_count + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0);
9601 
9602  // Tooltip on hover
9603  int v_hovered = -1;
9604  if (hovered)
9605  {
9606  const float t = ImClamp((g.IO.MousePos.x - inner_bb.Min.x) / (inner_bb.Max.x - inner_bb.Min.x), 0.0f, 0.9999f);
9607  const int v_idx = (int)(t * item_count);
9608  IM_ASSERT(v_idx >= 0 && v_idx < values_count);
9609 
9610  const float v0 = values_getter(data, (v_idx + values_offset) % values_count);
9611  const float v1 = values_getter(data, (v_idx + 1 + values_offset) % values_count);
9612  if (plot_type == ImGuiPlotType_Lines)
9613  SetTooltip("%d: %8.4g\n%d: %8.4g", v_idx, v0, v_idx+1, v1);
9614  else if (plot_type == ImGuiPlotType_Histogram)
9615  SetTooltip("%d: %8.4g", v_idx, v0);
9616  v_hovered = v_idx;
9617  }
9618 
9619  const float t_step = 1.0f / (float)res_w;
9620  const float inv_scale = (scale_min == scale_max) ? 0.0f : (1.0f / (scale_max - scale_min));
9621 
9622  float v0 = values_getter(data, (0 + values_offset) % values_count);
9623  float t0 = 0.0f;
9624  ImVec2 tp0 = ImVec2( t0, 1.0f - ImSaturate((v0 - scale_min) * inv_scale) ); // Point in the normalized space of our target rectangle
9625  float histogram_zero_line_t = (scale_min * scale_max < 0.0f) ? (-scale_min * inv_scale) : (scale_min < 0.0f ? 0.0f : 1.0f); // Where does the zero line stands
9626 
9627  const ImU32 col_base = GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLines : ImGuiCol_PlotHistogram);
9629 
9630  for (int n = 0; n < res_w; n++)
9631  {
9632  const float t1 = t0 + t_step;
9633  const int v1_idx = (int)(t0 * item_count + 0.5f);
9634  IM_ASSERT(v1_idx >= 0 && v1_idx < values_count);
9635  const float v1 = values_getter(data, (v1_idx + values_offset + 1) % values_count);
9636  const ImVec2 tp1 = ImVec2( t1, 1.0f - ImSaturate((v1 - scale_min) * inv_scale) );
9637 
9638  // NB: Draw calls are merged together by the DrawList system. Still, we should render our batch are lower level to save a bit of CPU.
9639  ImVec2 pos0 = ImLerp(inner_bb.Min, inner_bb.Max, tp0);
9640  ImVec2 pos1 = ImLerp(inner_bb.Min, inner_bb.Max, (plot_type == ImGuiPlotType_Lines) ? tp1 : ImVec2(tp1.x, histogram_zero_line_t));
9641  if (plot_type == ImGuiPlotType_Lines)
9642  {
9643  window->DrawList->AddLine(pos0, pos1, v_hovered == v1_idx ? col_hovered : col_base);
9644  }
9645  else if (plot_type == ImGuiPlotType_Histogram)
9646  {
9647  if (pos1.x >= pos0.x + 2.0f)
9648  pos1.x -= 1.0f;
9649  window->DrawList->AddRectFilled(pos0, pos1, v_hovered == v1_idx ? col_hovered : col_base);
9650  }
9651 
9652  t0 = t1;
9653  tp0 = tp1;
9654  }
9655  }
9656 
9657  // Text overlay
9658  if (overlay_text)
9659  RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, overlay_text, NULL, NULL, ImVec2(0.5f,0.0f));
9660 
9661  if (label_size.x > 0.0f)
9662  RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label);
9663 }
9664 
9666 {
9667  const float* Values;
9668  int Stride;
9669 
9671 };
9672 
9673 static float Plot_ArrayGetter(void* data, int idx)
9674 {
9676  const float v = *(const float*)(const void*)((const unsigned char*)plot_data->Values + (size_t)idx * plot_data->Stride);
9677  return v;
9678 }
9679 
9680 void ImGui::PlotLines(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride)
9681 {
9682  ImGuiPlotArrayGetterData data(values, stride);
9683  PlotEx(ImGuiPlotType_Lines, label, &Plot_ArrayGetter, (void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size);
9684 }
9685 
9686 void ImGui::PlotLines(const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size)
9687 {
9688  PlotEx(ImGuiPlotType_Lines, label, values_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size);
9689 }
9690 
9691 void ImGui::PlotHistogram(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride)
9692 {
9693  ImGuiPlotArrayGetterData data(values, stride);
9694  PlotEx(ImGuiPlotType_Histogram, label, &Plot_ArrayGetter, (void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size);
9695 }
9696 
9697 void ImGui::PlotHistogram(const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size)
9698 {
9699  PlotEx(ImGuiPlotType_Histogram, label, values_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size);
9700 }
9701 
9702 // size_arg (for each axis) < 0.0f: align to end, 0.0f: auto, > 0.0f: specified size
9703 void ImGui::ProgressBar(float fraction, const ImVec2& size_arg, const char* overlay)
9704 {
9705  ImGuiWindow* window = GetCurrentWindow();
9706  if (window->SkipItems)
9707  return;
9708 
9709  ImGuiContext& g = *GImGui;
9710  const ImGuiStyle& style = g.Style;
9711 
9712  ImVec2 pos = window->DC.CursorPos;
9713  ImRect bb(pos, pos + CalcItemSize(size_arg, CalcItemWidth(), g.FontSize + style.FramePadding.y*2.0f));
9714  ItemSize(bb, style.FramePadding.y);
9715  if (!ItemAdd(bb, 0))
9716  return;
9717 
9718  // Render
9719  fraction = ImSaturate(fraction);
9721  bb.Expand(ImVec2(-style.FrameBorderSize, -style.FrameBorderSize));
9722  const ImVec2 fill_br = ImVec2(ImLerp(bb.Min.x, bb.Max.x, fraction), bb.Max.y);
9723  RenderRectFilledRangeH(window->DrawList, bb, GetColorU32(ImGuiCol_PlotHistogram), 0.0f, fraction, style.FrameRounding);
9724 
9725  // Default displaying the fraction as percentage string, but user can override it
9726  char overlay_buf[32];
9727  if (!overlay)
9728  {
9729  ImFormatString(overlay_buf, IM_ARRAYSIZE(overlay_buf), "%.0f%%", fraction*100+0.01f);
9730  overlay = overlay_buf;
9731  }
9732 
9733  ImVec2 overlay_size = CalcTextSize(overlay, NULL);
9734  if (overlay_size.x > 0.0f)
9735  RenderTextClipped(ImVec2(ImClamp(fill_br.x + style.ItemSpacing.x, bb.Min.x, bb.Max.x - overlay_size.x - style.ItemInnerSpacing.x), bb.Min.y), bb.Max, overlay, NULL, &overlay_size, ImVec2(0.0f,0.5f), &bb);
9736 }
9737 
9738 bool ImGui::Checkbox(const char* label, bool* v)
9739 {
9740  ImGuiWindow* window = GetCurrentWindow();
9741  if (window->SkipItems)
9742  return false;
9743 
9744  ImGuiContext& g = *GImGui;
9745  const ImGuiStyle& style = g.Style;
9746  const ImGuiID id = window->GetID(label);
9747  const ImVec2 label_size = CalcTextSize(label, NULL, true);
9748 
9749  const ImRect check_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(label_size.y + style.FramePadding.y*2, label_size.y + style.FramePadding.y*2)); // We want a square shape to we use Y twice
9750  ItemSize(check_bb, style.FramePadding.y);
9751 
9752  ImRect total_bb = check_bb;
9753  if (label_size.x > 0)
9754  SameLine(0, style.ItemInnerSpacing.x);
9755  const ImRect text_bb(window->DC.CursorPos + ImVec2(0,style.FramePadding.y), window->DC.CursorPos + ImVec2(0,style.FramePadding.y) + label_size);
9756  if (label_size.x > 0)
9757  {
9758  ItemSize(ImVec2(text_bb.GetWidth(), check_bb.GetHeight()), style.FramePadding.y);
9759  total_bb = ImRect(ImMin(check_bb.Min, text_bb.Min), ImMax(check_bb.Max, text_bb.Max));
9760  }
9761 
9762  if (!ItemAdd(total_bb, id))
9763  return false;
9764 
9765  bool hovered, held;
9766  bool pressed = ButtonBehavior(total_bb, id, &hovered, &held);
9767  if (pressed)
9768  *v = !(*v);
9769 
9770  RenderNavHighlight(total_bb, id);
9771  RenderFrame(check_bb.Min, check_bb.Max, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding);
9772  if (*v)
9773  {
9774  const float check_sz = ImMin(check_bb.GetWidth(), check_bb.GetHeight());
9775  const float pad = ImMax(1.0f, (float)(int)(check_sz / 6.0f));
9776  RenderCheckMark(check_bb.Min + ImVec2(pad,pad), GetColorU32(ImGuiCol_CheckMark), check_bb.GetWidth() - pad*2.0f);
9777  }
9778 
9779  if (g.LogEnabled)
9780  LogRenderedText(&text_bb.Min, *v ? "[x]" : "[ ]");
9781  if (label_size.x > 0.0f)
9782  RenderText(text_bb.Min, label);
9783 
9784  return pressed;
9785 }
9786 
9787 bool ImGui::CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value)
9788 {
9789  bool v = ((*flags & flags_value) == flags_value);
9790  bool pressed = Checkbox(label, &v);
9791  if (pressed)
9792  {
9793  if (v)
9794  *flags |= flags_value;
9795  else
9796  *flags &= ~flags_value;
9797  }
9798 
9799  return pressed;
9800 }
9801 
9802 bool ImGui::RadioButton(const char* label, bool active)
9803 {
9804  ImGuiWindow* window = GetCurrentWindow();
9805  if (window->SkipItems)
9806  return false;
9807 
9808  ImGuiContext& g = *GImGui;
9809  const ImGuiStyle& style = g.Style;
9810  const ImGuiID id = window->GetID(label);
9811  const ImVec2 label_size = CalcTextSize(label, NULL, true);
9812 
9813  const ImRect check_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(label_size.y + style.FramePadding.y*2-1, label_size.y + style.FramePadding.y*2-1));
9814  ItemSize(check_bb, style.FramePadding.y);
9815 
9816  ImRect total_bb = check_bb;
9817  if (label_size.x > 0)
9818  SameLine(0, style.ItemInnerSpacing.x);
9819  const ImRect text_bb(window->DC.CursorPos + ImVec2(0, style.FramePadding.y), window->DC.CursorPos + ImVec2(0, style.FramePadding.y) + label_size);
9820  if (label_size.x > 0)
9821  {
9822  ItemSize(ImVec2(text_bb.GetWidth(), check_bb.GetHeight()), style.FramePadding.y);
9823  total_bb.Add(text_bb);
9824  }
9825 
9826  if (!ItemAdd(total_bb, id))
9827  return false;
9828 
9829  ImVec2 center = check_bb.GetCenter();
9830  center.x = (float)(int)center.x + 0.5f;
9831  center.y = (float)(int)center.y + 0.5f;
9832  const float radius = check_bb.GetHeight() * 0.5f;
9833 
9834  bool hovered, held;
9835  bool pressed = ButtonBehavior(total_bb, id, &hovered, &held);
9836 
9837  RenderNavHighlight(total_bb, id);
9838  window->DrawList->AddCircleFilled(center, radius, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), 16);
9839  if (active)
9840  {
9841  const float check_sz = ImMin(check_bb.GetWidth(), check_bb.GetHeight());
9842  const float pad = ImMax(1.0f, (float)(int)(check_sz / 6.0f));
9843  window->DrawList->AddCircleFilled(center, radius-pad, GetColorU32(ImGuiCol_CheckMark), 16);
9844  }
9845 
9846  if (style.FrameBorderSize > 0.0f)
9847  {
9848  window->DrawList->AddCircle(center+ImVec2(1,1), radius, GetColorU32(ImGuiCol_BorderShadow), 16, style.FrameBorderSize);
9849  window->DrawList->AddCircle(center, radius, GetColorU32(ImGuiCol_Border), 16, style.FrameBorderSize);
9850  }
9851 
9852  if (g.LogEnabled)
9853  LogRenderedText(&text_bb.Min, active ? "(x)" : "( )");
9854  if (label_size.x > 0.0f)
9855  RenderText(text_bb.Min, label);
9856 
9857  return pressed;
9858 }
9859 
9860 bool ImGui::RadioButton(const char* label, int* v, int v_button)
9861 {
9862  const bool pressed = RadioButton(label, *v == v_button);
9863  if (pressed)
9864  {
9865  *v = v_button;
9866  }
9867  return pressed;
9868 }
9869 
9870 static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end)
9871 {
9872  int line_count = 0;
9873  const char* s = text_begin;
9874  while (char c = *s++) // We are only matching for \n so we can ignore UTF-8 decoding
9875  if (c == '\n')
9876  line_count++;
9877  s--;
9878  if (s[0] != '\n' && s[0] != '\r')
9879  line_count++;
9880  *out_text_end = s;
9881  return line_count;
9882 }
9883 
9884 static ImVec2 InputTextCalcTextSizeW(const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining, ImVec2* out_offset, bool stop_on_new_line)
9885 {
9886  ImFont* font = GImGui->Font;
9887  const float line_height = GImGui->FontSize;
9888  const float scale = line_height / font->FontSize;
9889 
9890  ImVec2 text_size = ImVec2(0,0);
9891  float line_width = 0.0f;
9892 
9893  const ImWchar* s = text_begin;
9894  while (s < text_end)
9895  {
9896  unsigned int c = (unsigned int)(*s++);
9897  if (c == '\n')
9898  {
9899  text_size.x = ImMax(text_size.x, line_width);
9900  text_size.y += line_height;
9901  line_width = 0.0f;
9902  if (stop_on_new_line)
9903  break;
9904  continue;
9905  }
9906  if (c == '\r')
9907  continue;
9908 
9909  const float char_width = font->GetCharAdvance((unsigned short)c) * scale;
9910  line_width += char_width;
9911  }
9912 
9913  if (text_size.x < line_width)
9914  text_size.x = line_width;
9915 
9916  if (out_offset)
9917  *out_offset = ImVec2(line_width, text_size.y + line_height); // offset allow for the possibility of sitting after a trailing \n
9918 
9919  if (line_width > 0 || text_size.y == 0.0f) // whereas size.y will ignore the trailing \n
9920  text_size.y += line_height;
9921 
9922  if (remaining)
9923  *remaining = s;
9924 
9925  return text_size;
9926 }
9927 
9928 // Wrapper for stb_textedit.h to edit text (our wrapper is for: statically sized buffer, single-line, wchar characters. InputText converts between UTF-8 and wchar)
9929 namespace ImGuiStb
9930 {
9931 
9932 static int STB_TEXTEDIT_STRINGLEN(const STB_TEXTEDIT_STRING* obj) { return obj->CurLenW; }
9933 static ImWchar STB_TEXTEDIT_GETCHAR(const STB_TEXTEDIT_STRING* obj, int idx) { return obj->Text[idx]; }
9934 static float STB_TEXTEDIT_GETWIDTH(STB_TEXTEDIT_STRING* obj, int line_start_idx, int char_idx) { ImWchar c = obj->Text[line_start_idx+char_idx]; if (c == '\n') return STB_TEXTEDIT_GETWIDTH_NEWLINE; return GImGui->Font->GetCharAdvance(c) * (GImGui->FontSize / GImGui->Font->FontSize); }
9935 static int STB_TEXTEDIT_KEYTOTEXT(int key) { return key >= 0x10000 ? 0 : key; }
9936 static ImWchar STB_TEXTEDIT_NEWLINE = '\n';
9937 static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, STB_TEXTEDIT_STRING* obj, int line_start_idx)
9938 {
9939  const ImWchar* text = obj->Text.Data;
9940  const ImWchar* text_remaining = NULL;
9941  const ImVec2 size = InputTextCalcTextSizeW(text + line_start_idx, text + obj->CurLenW, &text_remaining, NULL, true);
9942  r->x0 = 0.0f;
9943  r->x1 = size.x;
9944  r->baseline_y_delta = size.y;
9945  r->ymin = 0.0f;
9946  r->ymax = size.y;
9947  r->num_chars = (int)(text_remaining - (text + line_start_idx));
9948 }
9949 
9950 static bool is_separator(unsigned int c) { return ImCharIsBlankW(c) || c==',' || c==';' || c=='(' || c==')' || c=='{' || c=='}' || c=='[' || c==']' || c=='|'; }
9951 static int is_word_boundary_from_right(STB_TEXTEDIT_STRING* obj, int idx) { return idx > 0 ? (is_separator( obj->Text[idx-1] ) && !is_separator( obj->Text[idx] ) ) : 1; }
9952 static int STB_TEXTEDIT_MOVEWORDLEFT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { idx--; while (idx >= 0 && !is_word_boundary_from_right(obj, idx)) idx--; return idx < 0 ? 0 : idx; }
9953 #ifdef __APPLE__ // FIXME: Move setting to IO structure
9954 static int is_word_boundary_from_left(STB_TEXTEDIT_STRING* obj, int idx) { return idx > 0 ? (!is_separator( obj->Text[idx-1] ) && is_separator( obj->Text[idx] ) ) : 1; }
9955 static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_left(obj, idx)) idx++; return idx > len ? len : idx; }
9956 #else
9957 static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_right(obj, idx)) idx++; return idx > len ? len : idx; }
9958 #endif
9959 #define STB_TEXTEDIT_MOVEWORDLEFT STB_TEXTEDIT_MOVEWORDLEFT_IMPL // They need to be #define for stb_textedit.h
9960 #define STB_TEXTEDIT_MOVEWORDRIGHT STB_TEXTEDIT_MOVEWORDRIGHT_IMPL
9961 
9962 static void STB_TEXTEDIT_DELETECHARS(STB_TEXTEDIT_STRING* obj, int pos, int n)
9963 {
9964  ImWchar* dst = obj->Text.Data + pos;
9965 
9966  // We maintain our buffer length in both UTF-8 and wchar formats
9967  obj->CurLenA -= ImTextCountUtf8BytesFromStr(dst, dst + n);
9968  obj->CurLenW -= n;
9969 
9970  // Offset remaining text
9971  const ImWchar* src = obj->Text.Data + pos + n;
9972  while (ImWchar c = *src++)
9973  *dst++ = c;
9974  *dst = '\0';
9975 }
9976 
9977 static bool STB_TEXTEDIT_INSERTCHARS(STB_TEXTEDIT_STRING* obj, int pos, const ImWchar* new_text, int new_text_len)
9978 {
9979  const int text_len = obj->CurLenW;
9980  IM_ASSERT(pos <= text_len);
9981  if (new_text_len + text_len + 1 > obj->Text.Size)
9982  return false;
9983 
9984  const int new_text_len_utf8 = ImTextCountUtf8BytesFromStr(new_text, new_text + new_text_len);
9985  if (new_text_len_utf8 + obj->CurLenA + 1 > obj->BufSizeA)
9986  return false;
9987 
9988  ImWchar* text = obj->Text.Data;
9989  if (pos != text_len)
9990  memmove(text + pos + new_text_len, text + pos, (size_t)(text_len - pos) * sizeof(ImWchar));
9991  memcpy(text + pos, new_text, (size_t)new_text_len * sizeof(ImWchar));
9992 
9993  obj->CurLenW += new_text_len;
9994  obj->CurLenA += new_text_len_utf8;
9995  obj->Text[obj->CurLenW] = '\0';
9996 
9997  return true;
9998 }
9999 
10000 // We don't use an enum so we can build even with conflicting symbols (if another user of stb_textedit.h leak their STB_TEXTEDIT_K_* symbols)
10001 #define STB_TEXTEDIT_K_LEFT 0x10000 // keyboard input to move cursor left
10002 #define STB_TEXTEDIT_K_RIGHT 0x10001 // keyboard input to move cursor right
10003 #define STB_TEXTEDIT_K_UP 0x10002 // keyboard input to move cursor up
10004 #define STB_TEXTEDIT_K_DOWN 0x10003 // keyboard input to move cursor down
10005 #define STB_TEXTEDIT_K_LINESTART 0x10004 // keyboard input to move cursor to start of line
10006 #define STB_TEXTEDIT_K_LINEEND 0x10005 // keyboard input to move cursor to end of line
10007 #define STB_TEXTEDIT_K_TEXTSTART 0x10006 // keyboard input to move cursor to start of text
10008 #define STB_TEXTEDIT_K_TEXTEND 0x10007 // keyboard input to move cursor to end of text
10009 #define STB_TEXTEDIT_K_DELETE 0x10008 // keyboard input to delete selection or character under cursor
10010 #define STB_TEXTEDIT_K_BACKSPACE 0x10009 // keyboard input to delete selection or character left of cursor
10011 #define STB_TEXTEDIT_K_UNDO 0x1000A // keyboard input to perform undo
10012 #define STB_TEXTEDIT_K_REDO 0x1000B // keyboard input to perform redo
10013 #define STB_TEXTEDIT_K_WORDLEFT 0x1000C // keyboard input to move cursor left one word
10014 #define STB_TEXTEDIT_K_WORDRIGHT 0x1000D // keyboard input to move cursor right one word
10015 #define STB_TEXTEDIT_K_SHIFT 0x20000
10016 
10017 #define STB_TEXTEDIT_IMPLEMENTATION
10018 #include "stb_textedit.h"
10019 
10020 }
10021 
10023 {
10024  stb_textedit_key(this, &StbState, key);
10025  CursorFollow = true;
10026  CursorAnimReset();
10027 }
10028 
10029 // Public API to manipulate UTF-8 text
10030 // We expose UTF-8 to the user (unlike the STB_TEXTEDIT_* functions which are manipulating wchar)
10031 // FIXME: The existence of this rarely exercised code path is a bit of a nuisance.
10032 void ImGuiTextEditCallbackData::DeleteChars(int pos, int bytes_count)
10033 {
10034  IM_ASSERT(pos + bytes_count <= BufTextLen);
10035  char* dst = Buf + pos;
10036  const char* src = Buf + pos + bytes_count;
10037  while (char c = *src++)
10038  *dst++ = c;
10039  *dst = '\0';
10040 
10041  if (CursorPos + bytes_count >= pos)
10042  CursorPos -= bytes_count;
10043  else if (CursorPos >= pos)
10044  CursorPos = pos;
10046  BufDirty = true;
10047  BufTextLen -= bytes_count;
10048 }
10049 
10050 void ImGuiTextEditCallbackData::InsertChars(int pos, const char* new_text, const char* new_text_end)
10051 {
10052  const int new_text_len = new_text_end ? (int)(new_text_end - new_text) : (int)strlen(new_text);
10053  if (new_text_len + BufTextLen + 1 >= BufSize)
10054  return;
10055 
10056  if (BufTextLen != pos)
10057  memmove(Buf + pos + new_text_len, Buf + pos, (size_t)(BufTextLen - pos));
10058  memcpy(Buf + pos, new_text, (size_t)new_text_len * sizeof(char));
10059  Buf[BufTextLen + new_text_len] = '\0';
10060 
10061  if (CursorPos >= pos)
10062  CursorPos += new_text_len;
10064  BufDirty = true;
10065  BufTextLen += new_text_len;
10066 }
10067 
10068 // Return false to discard a character.
10069 static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data)
10070 {
10071  unsigned int c = *p_char;
10072 
10073  if (c < 128 && c != ' ' && !isprint((int)(c & 0xFF)))
10074  {
10075  bool pass = false;
10076  pass |= (c == '\n' && (flags & ImGuiInputTextFlags_Multiline));
10077  pass |= (c == '\t' && (flags & ImGuiInputTextFlags_AllowTabInput));
10078  if (!pass)
10079  return false;
10080  }
10081 
10082  if (c >= 0xE000 && c <= 0xF8FF) // Filter private Unicode range. I don't imagine anybody would want to input them. GLFW on OSX seems to send private characters for special keys like arrow keys.
10083  return false;
10084 
10086  {
10088  if (!(c >= '0' && c <= '9') && (c != '.') && (c != '-') && (c != '+') && (c != '*') && (c != '/'))
10089  return false;
10090 
10092  if (!(c >= '0' && c <= '9') && (c != '.') && (c != '-') && (c != '+') && (c != '*') && (c != '/') && (c != 'e') && (c != 'E'))
10093  return false;
10094 
10096  if (!(c >= '0' && c <= '9') && !(c >= 'a' && c <= 'f') && !(c >= 'A' && c <= 'F'))
10097  return false;
10098 
10100  if (c >= 'a' && c <= 'z')
10101  *p_char = (c += (unsigned int)('A'-'a'));
10102 
10104  if (ImCharIsBlankW(c))
10105  return false;
10106  }
10107 
10109  {
10110  ImGuiTextEditCallbackData callback_data;
10111  memset(&callback_data, 0, sizeof(ImGuiTextEditCallbackData));
10113  callback_data.EventChar = (ImWchar)c;
10114  callback_data.Flags = flags;
10115  callback_data.UserData = user_data;
10116  if (callback(&callback_data) != 0)
10117  return false;
10118  *p_char = callback_data.EventChar;
10119  if (!callback_data.EventChar)
10120  return false;
10121  }
10122 
10123  return true;
10124 }
10125 
10126 // Edit a string of text
10127 // NB: when active, hold on a privately held copy of the text (and apply back to 'buf'). So changing 'buf' while active has no effect.
10128 // FIXME: Rather messy function partly because we are doing UTF8 > u16 > UTF8 conversions on the go to more easily handle stb_textedit calls. Ideally we should stay in UTF-8 all the time. See https://github.com/nothings/stb/issues/188
10129 bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data)
10130 {
10131  ImGuiWindow* window = GetCurrentWindow();
10132  if (window->SkipItems)
10133  return false;
10134 
10135  IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackHistory) && (flags & ImGuiInputTextFlags_Multiline))); // Can't use both together (they both use up/down keys)
10136  IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackCompletion) && (flags & ImGuiInputTextFlags_AllowTabInput))); // Can't use both together (they both use tab key)
10137 
10138  ImGuiContext& g = *GImGui;
10139  const ImGuiIO& io = g.IO;
10140  const ImGuiStyle& style = g.Style;
10141 
10142  const bool is_multiline = (flags & ImGuiInputTextFlags_Multiline) != 0;
10143  const bool is_editable = (flags & ImGuiInputTextFlags_ReadOnly) == 0;
10144  const bool is_password = (flags & ImGuiInputTextFlags_Password) != 0;
10145  const bool is_undoable = (flags & ImGuiInputTextFlags_NoUndoRedo) == 0;
10146 
10147  if (is_multiline) // Open group before calling GetID() because groups tracks id created during their spawn
10148  BeginGroup();
10149  const ImGuiID id = window->GetID(label);
10150  const ImVec2 label_size = CalcTextSize(label, NULL, true);
10151  ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), (is_multiline ? GetTextLineHeight() * 8.0f : label_size.y) + style.FramePadding.y*2.0f); // Arbitrary default of 8 lines high for multi-line
10152  const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size);
10153  const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? (style.ItemInnerSpacing.x + label_size.x) : 0.0f, 0.0f));
10154 
10155  ImGuiWindow* draw_window = window;
10156  if (is_multiline)
10157  {
10158  ItemAdd(total_bb, id, &frame_bb);
10159  if (!BeginChildFrame(id, frame_bb.GetSize()))
10160  {
10161  EndChildFrame();
10162  EndGroup();
10163  return false;
10164  }
10165  draw_window = GetCurrentWindow();
10166  size.x -= draw_window->ScrollbarSizes.x;
10167  }
10168  else
10169  {
10170  ItemSize(total_bb, style.FramePadding.y);
10171  if (!ItemAdd(total_bb, id, &frame_bb))
10172  return false;
10173  }
10174  const bool hovered = ItemHoverable(frame_bb, id);
10175  if (hovered)
10177 
10178  // Password pushes a temporary font with only a fallback glyph
10179  if (is_password)
10180  {
10181  const ImFontGlyph* glyph = g.Font->FindGlyph('*');
10182  ImFont* password_font = &g.InputTextPasswordFont;
10183  password_font->FontSize = g.Font->FontSize;
10184  password_font->Scale = g.Font->Scale;
10185  password_font->DisplayOffset = g.Font->DisplayOffset;
10186  password_font->Ascent = g.Font->Ascent;
10187  password_font->Descent = g.Font->Descent;
10188  password_font->ContainerAtlas = g.Font->ContainerAtlas;
10189  password_font->FallbackGlyph = glyph;
10190  password_font->FallbackAdvanceX = glyph->AdvanceX;
10191  IM_ASSERT(password_font->Glyphs.empty() && password_font->IndexAdvanceX.empty() && password_font->IndexLookup.empty());
10192  PushFont(password_font);
10193  }
10194 
10195  // NB: we are only allowed to access 'edit_state' if we are the active widget.
10196  ImGuiTextEditState& edit_state = g.InputTextState;
10197 
10198  const bool focus_requested = FocusableItemRegister(window, id, (flags & (ImGuiInputTextFlags_CallbackCompletion|ImGuiInputTextFlags_AllowTabInput)) == 0); // Using completion callback disable keyboard tabbing
10199  const bool focus_requested_by_code = focus_requested && (window->FocusIdxAllCounter == window->FocusIdxAllRequestCurrent);
10200  const bool focus_requested_by_tab = focus_requested && !focus_requested_by_code;
10201 
10202  const bool user_clicked = hovered && io.MouseClicked[0];
10203  const bool user_scrolled = is_multiline && g.ActiveId == 0 && edit_state.Id == id && g.ActiveIdPreviousFrame == draw_window->GetIDNoKeepAlive("#SCROLLY");
10204  const bool user_nav_input_start = (g.ActiveId != id) && ((g.NavInputId == id) || (g.NavActivateId == id && g.NavInputSource == ImGuiInputSource_NavKeyboard));
10205 
10206  bool clear_active_id = false;
10207 
10208  bool select_all = (g.ActiveId != id) && ((flags & ImGuiInputTextFlags_AutoSelectAll) != 0 || user_nav_input_start) && (!is_multiline);
10209  if (focus_requested || user_clicked || user_scrolled || user_nav_input_start)
10210  {
10211  if (g.ActiveId != id)
10212  {
10213  // Start edition
10214  // Take a copy of the initial buffer value (both in original UTF-8 format and converted to wchar)
10215  // From the moment we focused we are ignoring the content of 'buf' (unless we are in read-only mode)
10216  const int prev_len_w = edit_state.CurLenW;
10217  edit_state.Text.resize(buf_size+1); // wchar count <= UTF-8 count. we use +1 to make sure that .Data isn't NULL so it doesn't crash.
10218  edit_state.InitialText.resize(buf_size+1); // UTF-8. we use +1 to make sure that .Data isn't NULL so it doesn't crash.
10219  ImStrncpy(edit_state.InitialText.Data, buf, edit_state.InitialText.Size);
10220  const char* buf_end = NULL;
10221  edit_state.CurLenW = ImTextStrFromUtf8(edit_state.Text.Data, edit_state.Text.Size, buf, NULL, &buf_end);
10222  edit_state.CurLenA = (int)(buf_end - buf); // We can't get the result from ImFormatString() above because it is not UTF-8 aware. Here we'll cut off malformed UTF-8.
10223  edit_state.CursorAnimReset();
10224 
10225  // Preserve cursor position and undo/redo stack if we come back to same widget
10226  // FIXME: We should probably compare the whole buffer to be on the safety side. Comparing buf (utf8) and edit_state.Text (wchar).
10227  const bool recycle_state = (edit_state.Id == id) && (prev_len_w == edit_state.CurLenW);
10228  if (recycle_state)
10229  {
10230  // Recycle existing cursor/selection/undo stack but clamp position
10231  // Note a single mouse click will override the cursor/position immediately by calling stb_textedit_click handler.
10232  edit_state.CursorClamp();
10233  }
10234  else
10235  {
10236  edit_state.Id = id;
10237  edit_state.ScrollX = 0.0f;
10238  stb_textedit_initialize_state(&edit_state.StbState, !is_multiline);
10239  if (!is_multiline && focus_requested_by_code)
10240  select_all = true;
10241  }
10243  edit_state.StbState.insert_mode = true;
10244  if (!is_multiline && (focus_requested_by_tab || (user_clicked && io.KeyCtrl)))
10245  select_all = true;
10246  }
10247  SetActiveID(id, window);
10248  SetFocusID(id, window);
10249  FocusWindow(window);
10250  if (!is_multiline && !(flags & ImGuiInputTextFlags_CallbackHistory))
10251  g.ActiveIdAllowNavDirFlags |= ((1 << ImGuiDir_Up) | (1 << ImGuiDir_Down));
10252  }
10253  else if (io.MouseClicked[0])
10254  {
10255  // Release focus when we click outside
10256  clear_active_id = true;
10257  }
10258 
10259  bool value_changed = false;
10260  bool enter_pressed = false;
10261 
10262  if (g.ActiveId == id)
10263  {
10264  if (!is_editable && !g.ActiveIdIsJustActivated)
10265  {
10266  // When read-only we always use the live data passed to the function
10267  edit_state.Text.resize(buf_size+1);
10268  const char* buf_end = NULL;
10269  edit_state.CurLenW = ImTextStrFromUtf8(edit_state.Text.Data, edit_state.Text.Size, buf, NULL, &buf_end);
10270  edit_state.CurLenA = (int)(buf_end - buf);
10271  edit_state.CursorClamp();
10272  }
10273 
10274  edit_state.BufSizeA = buf_size;
10275 
10276  // Although we are active we don't prevent mouse from hovering other elements unless we are interacting right now with the widget.
10277  // Down the line we should have a cleaner library-wide concept of Selected vs Active.
10278  g.ActiveIdAllowOverlap = !io.MouseDown[0];
10279  g.WantTextInputNextFrame = 1;
10280 
10281  // Edit in progress
10282  const float mouse_x = (io.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + edit_state.ScrollX;
10283  const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y - style.FramePadding.y) : (g.FontSize*0.5f));
10284 
10285  const bool is_osx = io.OptMacOSXBehaviors;
10286  if (select_all || (hovered && !is_osx && io.MouseDoubleClicked[0]))
10287  {
10288  edit_state.SelectAll();
10289  edit_state.SelectedAllMouseLock = true;
10290  }
10291  else if (hovered && is_osx && io.MouseDoubleClicked[0])
10292  {
10293  // Double-click select a word only, OS X style (by simulating keystrokes)
10296  }
10297  else if (io.MouseClicked[0] && !edit_state.SelectedAllMouseLock)
10298  {
10299  if (hovered)
10300  {
10301  stb_textedit_click(&edit_state, &edit_state.StbState, mouse_x, mouse_y);
10302  edit_state.CursorAnimReset();
10303  }
10304  }
10305  else if (io.MouseDown[0] && !edit_state.SelectedAllMouseLock && (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f))
10306  {
10307  stb_textedit_drag(&edit_state, &edit_state.StbState, mouse_x, mouse_y);
10308  edit_state.CursorAnimReset();
10309  edit_state.CursorFollow = true;
10310  }
10311  if (edit_state.SelectedAllMouseLock && !io.MouseDown[0])
10312  edit_state.SelectedAllMouseLock = false;
10313 
10314  if (io.InputCharacters[0])
10315  {
10316  // Process text input (before we check for Return because using some IME will effectively send a Return?)
10317  // We ignore CTRL inputs, but need to allow ALT+CTRL as some keyboards (e.g. German) use AltGR (which _is_ Alt+Ctrl) to input certain characters.
10318  bool ignore_inputs = (io.KeyCtrl && !io.KeyAlt) || (is_osx && io.KeySuper);
10319  if (!ignore_inputs && is_editable && !user_nav_input_start)
10320  for (int n = 0; n < IM_ARRAYSIZE(io.InputCharacters) && io.InputCharacters[n]; n++)
10321  {
10322  // Insert character if they pass filtering
10323  unsigned int c = (unsigned int)io.InputCharacters[n];
10324  if (InputTextFilterCharacter(&c, flags, callback, user_data))
10325  edit_state.OnKeyPressed((int)c);
10326  }
10327 
10328  // Consume characters
10329  memset(g.IO.InputCharacters, 0, sizeof(g.IO.InputCharacters));
10330  }
10331  }
10332 
10333  bool cancel_edit = false;
10334  if (g.ActiveId == id && !g.ActiveIdIsJustActivated && !clear_active_id)
10335  {
10336  // Handle key-presses
10337  const int k_mask = (io.KeyShift ? STB_TEXTEDIT_K_SHIFT : 0);
10338  const bool is_osx = io.OptMacOSXBehaviors;
10339  const bool is_shortcut_key = (is_osx ? (io.KeySuper && !io.KeyCtrl) : (io.KeyCtrl && !io.KeySuper)) && !io.KeyAlt && !io.KeyShift; // OS X style: Shortcuts using Cmd/Super instead of Ctrl
10340  const bool is_osx_shift_shortcut = is_osx && io.KeySuper && io.KeyShift && !io.KeyCtrl && !io.KeyAlt;
10341  const bool is_wordmove_key_down = is_osx ? io.KeyAlt : io.KeyCtrl; // OS X style: Text editing cursor movement using Alt instead of Ctrl
10342  const bool is_startend_key_down = is_osx && io.KeySuper && !io.KeyCtrl && !io.KeyAlt; // OS X style: Line/Text Start and End using Cmd+Arrows instead of Home/End
10343  const bool is_ctrl_key_only = io.KeyCtrl && !io.KeyShift && !io.KeyAlt && !io.KeySuper;
10344  const bool is_shift_key_only = io.KeyShift && !io.KeyCtrl && !io.KeyAlt && !io.KeySuper;
10345 
10346  const bool is_cut = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_X)) || (is_shift_key_only && IsKeyPressedMap(ImGuiKey_Delete))) && is_editable && !is_password && (!is_multiline || edit_state.HasSelection());
10347  const bool is_copy = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_C)) || (is_ctrl_key_only && IsKeyPressedMap(ImGuiKey_Insert))) && !is_password && (!is_multiline || edit_state.HasSelection());
10348  const bool is_paste = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_V)) || (is_shift_key_only && IsKeyPressedMap(ImGuiKey_Insert))) && is_editable;
10349  const bool is_undo = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_Z)) && is_editable && is_undoable);
10350  const bool is_redo = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_Y)) || (is_osx_shift_shortcut && IsKeyPressedMap(ImGuiKey_Z))) && is_editable && is_undoable;
10351 
10352  if (IsKeyPressedMap(ImGuiKey_LeftArrow)) { edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask); }
10353  else if (IsKeyPressedMap(ImGuiKey_RightArrow)) { edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask); }
10354  else if (IsKeyPressedMap(ImGuiKey_UpArrow) && is_multiline) { if (io.KeyCtrl) SetWindowScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); }
10355  else if (IsKeyPressedMap(ImGuiKey_DownArrow) && is_multiline) { if (io.KeyCtrl) SetWindowScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); }
10356  else if (IsKeyPressedMap(ImGuiKey_Home)) { edit_state.OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); }
10357  else if (IsKeyPressedMap(ImGuiKey_End)) { edit_state.OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); }
10358  else if (IsKeyPressedMap(ImGuiKey_Delete) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); }
10359  else if (IsKeyPressedMap(ImGuiKey_Backspace) && is_editable)
10360  {
10361  if (!edit_state.HasSelection())
10362  {
10363  if (is_wordmove_key_down) edit_state.OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT|STB_TEXTEDIT_K_SHIFT);
10364  else if (is_osx && io.KeySuper && !io.KeyAlt && !io.KeyCtrl) edit_state.OnKeyPressed(STB_TEXTEDIT_K_LINESTART|STB_TEXTEDIT_K_SHIFT);
10365  }
10366  edit_state.OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask);
10367  }
10368  else if (IsKeyPressedMap(ImGuiKey_Enter))
10369  {
10370  bool ctrl_enter_for_new_line = (flags & ImGuiInputTextFlags_CtrlEnterForNewLine) != 0;
10371  if (!is_multiline || (ctrl_enter_for_new_line && !io.KeyCtrl) || (!ctrl_enter_for_new_line && io.KeyCtrl))
10372  {
10373  enter_pressed = clear_active_id = true;
10374  }
10375  else if (is_editable)
10376  {
10377  unsigned int c = '\n'; // Insert new line
10378  if (InputTextFilterCharacter(&c, flags, callback, user_data))
10379  edit_state.OnKeyPressed((int)c);
10380  }
10381  }
10382  else if ((flags & ImGuiInputTextFlags_AllowTabInput) && IsKeyPressedMap(ImGuiKey_Tab) && !io.KeyCtrl && !io.KeyShift && !io.KeyAlt && is_editable)
10383  {
10384  unsigned int c = '\t'; // Insert TAB
10385  if (InputTextFilterCharacter(&c, flags, callback, user_data))
10386  edit_state.OnKeyPressed((int)c);
10387  }
10388  else if (IsKeyPressedMap(ImGuiKey_Escape))
10389  {
10390  clear_active_id = cancel_edit = true;
10391  }
10392  else if (is_undo || is_redo)
10393  {
10394  edit_state.OnKeyPressed(is_undo ? STB_TEXTEDIT_K_UNDO : STB_TEXTEDIT_K_REDO);
10395  edit_state.ClearSelection();
10396  }
10397  else if (is_shortcut_key && IsKeyPressedMap(ImGuiKey_A))
10398  {
10399  edit_state.SelectAll();
10400  edit_state.CursorFollow = true;
10401  }
10402  else if (is_cut || is_copy)
10403  {
10404  // Cut, Copy
10405  if (io.SetClipboardTextFn)
10406  {
10407  const int ib = edit_state.HasSelection() ? ImMin(edit_state.StbState.select_start, edit_state.StbState.select_end) : 0;
10408  const int ie = edit_state.HasSelection() ? ImMax(edit_state.StbState.select_start, edit_state.StbState.select_end) : edit_state.CurLenW;
10409  edit_state.TempTextBuffer.resize((ie-ib) * 4 + 1);
10410  ImTextStrToUtf8(edit_state.TempTextBuffer.Data, edit_state.TempTextBuffer.Size, edit_state.Text.Data+ib, edit_state.Text.Data+ie);
10411  SetClipboardText(edit_state.TempTextBuffer.Data);
10412  }
10413  if (is_cut)
10414  {
10415  if (!edit_state.HasSelection())
10416  edit_state.SelectAll();
10417  edit_state.CursorFollow = true;
10418  stb_textedit_cut(&edit_state, &edit_state.StbState);
10419  }
10420  }
10421  else if (is_paste)
10422  {
10423  if (const char* clipboard = GetClipboardText())
10424  {
10425  // Filter pasted buffer
10426  const int clipboard_len = (int)strlen(clipboard);
10427  ImWchar* clipboard_filtered = (ImWchar*)ImGui::MemAlloc((clipboard_len+1) * sizeof(ImWchar));
10428  int clipboard_filtered_len = 0;
10429  for (const char* s = clipboard; *s; )
10430  {
10431  unsigned int c;
10432  s += ImTextCharFromUtf8(&c, s, NULL);
10433  if (c == 0)
10434  break;
10435  if (c >= 0x10000 || !InputTextFilterCharacter(&c, flags, callback, user_data))
10436  continue;
10437  clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c;
10438  }
10439  clipboard_filtered[clipboard_filtered_len] = 0;
10440  if (clipboard_filtered_len > 0) // If everything was filtered, ignore the pasting operation
10441  {
10442  stb_textedit_paste(&edit_state, &edit_state.StbState, clipboard_filtered, clipboard_filtered_len);
10443  edit_state.CursorFollow = true;
10444  }
10445  ImGui::MemFree(clipboard_filtered);
10446  }
10447  }
10448  }
10449 
10450  if (g.ActiveId == id)
10451  {
10452  if (cancel_edit)
10453  {
10454  // Restore initial value. Only return true if restoring to the initial value changes the current buffer contents.
10455  if (is_editable && strncmp(buf, edit_state.InitialText.Data, buf_size) != 0)
10456  {
10457  ImStrncpy(buf, edit_state.InitialText.Data, buf_size);
10458  value_changed = true;
10459  }
10460  }
10461 
10462  // When using 'ImGuiInputTextFlags_EnterReturnsTrue' as a special case we reapply the live buffer back to the input buffer before clearing ActiveId, even though strictly speaking it wasn't modified on this frame.
10463  // If we didn't do that, code like InputInt() with ImGuiInputTextFlags_EnterReturnsTrue would fail. Also this allows the user to use InputText() with ImGuiInputTextFlags_EnterReturnsTrue without maintaining any user-side storage.
10464  bool apply_edit_back_to_user_buffer = !cancel_edit || (enter_pressed && (flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0);
10465  if (apply_edit_back_to_user_buffer)
10466  {
10467  // Apply new value immediately - copy modified buffer back
10468  // Note that as soon as the input box is active, the in-widget value gets priority over any underlying modification of the input buffer
10469  // FIXME: We actually always render 'buf' when calling DrawList->AddText, making the comment above incorrect.
10470  // FIXME-OPT: CPU waste to do this every time the widget is active, should mark dirty state from the stb_textedit callbacks.
10471  if (is_editable)
10472  {
10473  edit_state.TempTextBuffer.resize(edit_state.Text.Size * 4);
10474  ImTextStrToUtf8(edit_state.TempTextBuffer.Data, edit_state.TempTextBuffer.Size, edit_state.Text.Data, NULL);
10475  }
10476 
10477  // User callback
10478  if ((flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory | ImGuiInputTextFlags_CallbackAlways)) != 0)
10479  {
10480  IM_ASSERT(callback != NULL);
10481 
10482  // The reason we specify the usage semantic (Completion/History) is that Completion needs to disable keyboard TABBING at the moment.
10483  ImGuiInputTextFlags event_flag = 0;
10484  ImGuiKey event_key = ImGuiKey_COUNT;
10485  if ((flags & ImGuiInputTextFlags_CallbackCompletion) != 0 && IsKeyPressedMap(ImGuiKey_Tab))
10486  {
10488  event_key = ImGuiKey_Tab;
10489  }
10490  else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressedMap(ImGuiKey_UpArrow))
10491  {
10493  event_key = ImGuiKey_UpArrow;
10494  }
10495  else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressedMap(ImGuiKey_DownArrow))
10496  {
10498  event_key = ImGuiKey_DownArrow;
10499  }
10500  else if (flags & ImGuiInputTextFlags_CallbackAlways)
10502 
10503  if (event_flag)
10504  {
10505  ImGuiTextEditCallbackData callback_data;
10506  memset(&callback_data, 0, sizeof(ImGuiTextEditCallbackData));
10507  callback_data.EventFlag = event_flag;
10508  callback_data.Flags = flags;
10509  callback_data.UserData = user_data;
10510  callback_data.ReadOnly = !is_editable;
10511 
10512  callback_data.EventKey = event_key;
10513  callback_data.Buf = edit_state.TempTextBuffer.Data;
10514  callback_data.BufTextLen = edit_state.CurLenA;
10515  callback_data.BufSize = edit_state.BufSizeA;
10516  callback_data.BufDirty = false;
10517 
10518  // We have to convert from wchar-positions to UTF-8-positions, which can be pretty slow (an incentive to ditch the ImWchar buffer, see https://github.com/nothings/stb/issues/188)
10519  ImWchar* text = edit_state.Text.Data;
10520  const int utf8_cursor_pos = callback_data.CursorPos = ImTextCountUtf8BytesFromStr(text, text + edit_state.StbState.cursor);
10521  const int utf8_selection_start = callback_data.SelectionStart = ImTextCountUtf8BytesFromStr(text, text + edit_state.StbState.select_start);
10522  const int utf8_selection_end = callback_data.SelectionEnd = ImTextCountUtf8BytesFromStr(text, text + edit_state.StbState.select_end);
10523 
10524  // Call user code
10525  callback(&callback_data);
10526 
10527  // Read back what user may have modified
10528  IM_ASSERT(callback_data.Buf == edit_state.TempTextBuffer.Data); // Invalid to modify those fields
10529  IM_ASSERT(callback_data.BufSize == edit_state.BufSizeA);
10530  IM_ASSERT(callback_data.Flags == flags);
10531  if (callback_data.CursorPos != utf8_cursor_pos) edit_state.StbState.cursor = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.CursorPos);
10532  if (callback_data.SelectionStart != utf8_selection_start) edit_state.StbState.select_start = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionStart);
10533  if (callback_data.SelectionEnd != utf8_selection_end) edit_state.StbState.select_end = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionEnd);
10534  if (callback_data.BufDirty)
10535  {
10536  IM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text!
10537  edit_state.CurLenW = ImTextStrFromUtf8(edit_state.Text.Data, edit_state.Text.Size, callback_data.Buf, NULL);
10538  edit_state.CurLenA = callback_data.BufTextLen; // Assume correct length and valid UTF-8 from user, saves us an extra strlen()
10539  edit_state.CursorAnimReset();
10540  }
10541  }
10542  }
10543 
10544  // Copy back to user buffer
10545  if (is_editable && strcmp(edit_state.TempTextBuffer.Data, buf) != 0)
10546  {
10547  ImStrncpy(buf, edit_state.TempTextBuffer.Data, buf_size);
10548  value_changed = true;
10549  }
10550  }
10551  }
10552 
10553  // Release active ID at the end of the function (so e.g. pressing Return still does a final application of the value)
10554  if (clear_active_id && g.ActiveId == id)
10555  ClearActiveID();
10556 
10557  // Render
10558  // Select which buffer we are going to display. When ImGuiInputTextFlags_NoLiveEdit is set 'buf' might still be the old value. We set buf to NULL to prevent accidental usage from now on.
10559  const char* buf_display = (g.ActiveId == id && is_editable) ? edit_state.TempTextBuffer.Data : buf; buf = NULL;
10560 
10561  RenderNavHighlight(frame_bb, id);
10562  if (!is_multiline)
10563  RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
10564 
10565  const ImVec4 clip_rect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + size.x, frame_bb.Min.y + size.y); // Not using frame_bb.Max because we have adjusted size
10566  ImVec2 render_pos = is_multiline ? draw_window->DC.CursorPos : frame_bb.Min + style.FramePadding;
10567  ImVec2 text_size(0.f, 0.f);
10568  const bool is_currently_scrolling = (edit_state.Id == id && is_multiline && g.ActiveId == draw_window->GetIDNoKeepAlive("#SCROLLY"));
10569  if (g.ActiveId == id || is_currently_scrolling)
10570  {
10571  edit_state.CursorAnim += io.DeltaTime;
10572 
10573  // This is going to be messy. We need to:
10574  // - Display the text (this alone can be more easily clipped)
10575  // - Handle scrolling, highlight selection, display cursor (those all requires some form of 1d->2d cursor position calculation)
10576  // - Measure text height (for scrollbar)
10577  // We are attempting to do most of that in **one main pass** to minimize the computation cost (non-negligible for large amount of text) + 2nd pass for selection rendering (we could merge them by an extra refactoring effort)
10578  // FIXME: This should occur on buf_display but we'd need to maintain cursor/select_start/select_end for UTF-8.
10579  const ImWchar* text_begin = edit_state.Text.Data;
10580  ImVec2 cursor_offset, select_start_offset;
10581 
10582  {
10583  // Count lines + find lines numbers straddling 'cursor' and 'select_start' position.
10584  const ImWchar* searches_input_ptr[2];
10585  searches_input_ptr[0] = text_begin + edit_state.StbState.cursor;
10586  searches_input_ptr[1] = NULL;
10587  int searches_remaining = 1;
10588  int searches_result_line_number[2] = { -1, -999 };
10589  if (edit_state.StbState.select_start != edit_state.StbState.select_end)
10590  {
10591  searches_input_ptr[1] = text_begin + ImMin(edit_state.StbState.select_start, edit_state.StbState.select_end);
10592  searches_result_line_number[1] = -1;
10593  searches_remaining++;
10594  }
10595 
10596  // Iterate all lines to find our line numbers
10597  // In multi-line mode, we never exit the loop until all lines are counted, so add one extra to the searches_remaining counter.
10598  searches_remaining += is_multiline ? 1 : 0;
10599  int line_count = 0;
10600  for (const ImWchar* s = text_begin; *s != 0; s++)
10601  if (*s == '\n')
10602  {
10603  line_count++;
10604  if (searches_result_line_number[0] == -1 && s >= searches_input_ptr[0]) { searches_result_line_number[0] = line_count; if (--searches_remaining <= 0) break; }
10605  if (searches_result_line_number[1] == -1 && s >= searches_input_ptr[1]) { searches_result_line_number[1] = line_count; if (--searches_remaining <= 0) break; }
10606  }
10607  line_count++;
10608  if (searches_result_line_number[0] == -1) searches_result_line_number[0] = line_count;
10609  if (searches_result_line_number[1] == -1) searches_result_line_number[1] = line_count;
10610 
10611  // Calculate 2d position by finding the beginning of the line and measuring distance
10612  cursor_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[0], text_begin), searches_input_ptr[0]).x;
10613  cursor_offset.y = searches_result_line_number[0] * g.FontSize;
10614  if (searches_result_line_number[1] >= 0)
10615  {
10616  select_start_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[1], text_begin), searches_input_ptr[1]).x;
10617  select_start_offset.y = searches_result_line_number[1] * g.FontSize;
10618  }
10619 
10620  // Store text height (note that we haven't calculated text width at all, see GitHub issues #383, #1224)
10621  if (is_multiline)
10622  text_size = ImVec2(size.x, line_count * g.FontSize);
10623  }
10624 
10625  // Scroll
10626  if (edit_state.CursorFollow)
10627  {
10628  // Horizontal scroll in chunks of quarter width
10630  {
10631  const float scroll_increment_x = size.x * 0.25f;
10632  if (cursor_offset.x < edit_state.ScrollX)
10633  edit_state.ScrollX = (float)(int)ImMax(0.0f, cursor_offset.x - scroll_increment_x);
10634  else if (cursor_offset.x - size.x >= edit_state.ScrollX)
10635  edit_state.ScrollX = (float)(int)(cursor_offset.x - size.x + scroll_increment_x);
10636  }
10637  else
10638  {
10639  edit_state.ScrollX = 0.0f;
10640  }
10641 
10642  // Vertical scroll
10643  if (is_multiline)
10644  {
10645  float scroll_y = draw_window->Scroll.y;
10646  if (cursor_offset.y - g.FontSize < scroll_y)
10647  scroll_y = ImMax(0.0f, cursor_offset.y - g.FontSize);
10648  else if (cursor_offset.y - size.y >= scroll_y)
10649  scroll_y = cursor_offset.y - size.y;
10650  draw_window->DC.CursorPos.y += (draw_window->Scroll.y - scroll_y); // To avoid a frame of lag
10651  draw_window->Scroll.y = scroll_y;
10652  render_pos.y = draw_window->DC.CursorPos.y;
10653  }
10654  }
10655  edit_state.CursorFollow = false;
10656  const ImVec2 render_scroll = ImVec2(edit_state.ScrollX, 0.0f);
10657 
10658  // Draw selection
10659  if (edit_state.StbState.select_start != edit_state.StbState.select_end)
10660  {
10661  const ImWchar* text_selected_begin = text_begin + ImMin(edit_state.StbState.select_start, edit_state.StbState.select_end);
10662  const ImWchar* text_selected_end = text_begin + ImMax(edit_state.StbState.select_start, edit_state.StbState.select_end);
10663 
10664  float bg_offy_up = is_multiline ? 0.0f : -1.0f; // FIXME: those offsets should be part of the style? they don't play so well with multi-line selection.
10665  float bg_offy_dn = is_multiline ? 0.0f : 2.0f;
10667  ImVec2 rect_pos = render_pos + select_start_offset - render_scroll;
10668  for (const ImWchar* p = text_selected_begin; p < text_selected_end; )
10669  {
10670  if (rect_pos.y > clip_rect.w + g.FontSize)
10671  break;
10672  if (rect_pos.y < clip_rect.y)
10673  {
10674  while (p < text_selected_end)
10675  if (*p++ == '\n')
10676  break;
10677  }
10678  else
10679  {
10680  ImVec2 rect_size = InputTextCalcTextSizeW(p, text_selected_end, &p, NULL, true);
10681  if (rect_size.x <= 0.0f) rect_size.x = (float)(int)(g.Font->GetCharAdvance((unsigned short)' ') * 0.50f); // So we can see selected empty lines
10682  ImRect rect(rect_pos + ImVec2(0.0f, bg_offy_up - g.FontSize), rect_pos +ImVec2(rect_size.x, bg_offy_dn));
10683  rect.ClipWith(clip_rect);
10684  if (rect.Overlaps(clip_rect))
10685  draw_window->DrawList->AddRectFilled(rect.Min, rect.Max, bg_color);
10686  }
10687  rect_pos.x = render_pos.x - render_scroll.x;
10688  rect_pos.y += g.FontSize;
10689  }
10690  }
10691 
10692  draw_window->DrawList->AddText(g.Font, g.FontSize, render_pos - render_scroll, GetColorU32(ImGuiCol_Text), buf_display, buf_display + edit_state.CurLenA, 0.0f, is_multiline ? NULL : &clip_rect);
10693 
10694  // Draw blinking cursor
10695  bool cursor_is_visible = (!g.IO.OptCursorBlink) || (g.InputTextState.CursorAnim <= 0.0f) || ImFmod(g.InputTextState.CursorAnim, 1.20f) <= 0.80f;
10696  ImVec2 cursor_screen_pos = render_pos + cursor_offset - render_scroll;
10697  ImRect cursor_screen_rect(cursor_screen_pos.x, cursor_screen_pos.y-g.FontSize+0.5f, cursor_screen_pos.x+1.0f, cursor_screen_pos.y-1.5f);
10698  if (cursor_is_visible && cursor_screen_rect.Overlaps(clip_rect))
10699  draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.GetBL(), GetColorU32(ImGuiCol_Text));
10700 
10701  // Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.)
10702  if (is_editable)
10703  g.PlatformImePos = ImVec2(cursor_screen_pos.x - 1, cursor_screen_pos.y - g.FontSize);
10704  }
10705  else
10706  {
10707  // Render text only
10708  const char* buf_end = NULL;
10709  if (is_multiline)
10710  text_size = ImVec2(size.x, InputTextCalcTextLenAndLineCount(buf_display, &buf_end) * g.FontSize); // We don't need width
10711  draw_window->DrawList->AddText(g.Font, g.FontSize, render_pos, GetColorU32(ImGuiCol_Text), buf_display, buf_end, 0.0f, is_multiline ? NULL : &clip_rect);
10712  }
10713 
10714  if (is_multiline)
10715  {
10716  Dummy(text_size + ImVec2(0.0f, g.FontSize)); // Always add room to scroll an extra line
10717  EndChildFrame();
10718  EndGroup();
10719  }
10720 
10721  if (is_password)
10722  PopFont();
10723 
10724  // Log as text
10725  if (g.LogEnabled && !is_password)
10726  LogRenderedText(&render_pos, buf_display, NULL);
10727 
10728  if (label_size.x > 0)
10729  RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
10730 
10731  if ((flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0)
10732  return enter_pressed;
10733  else
10734  return value_changed;
10735 }
10736 
10737 bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data)
10738 {
10739  IM_ASSERT(!(flags & ImGuiInputTextFlags_Multiline)); // call InputTextMultiline()
10740  return InputTextEx(label, buf, (int)buf_size, ImVec2(0,0), flags, callback, user_data);
10741 }
10742 
10743 bool ImGui::InputTextMultiline(const char* label, char* buf, size_t buf_size, const ImVec2& size, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data)
10744 {
10745  return InputTextEx(label, buf, (int)buf_size, size, flags | ImGuiInputTextFlags_Multiline, callback, user_data);
10746 }
10747 
10748 // NB: format here must be a simple "%xx" format string with no prefix/suffix (unlike the Drag/Slider functions "format" argument)
10749 bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_ptr, const void* step, const void* step_fast, const char* format, ImGuiInputTextFlags extra_flags)
10750 {
10751  ImGuiWindow* window = GetCurrentWindow();
10752  if (window->SkipItems)
10753  return false;
10754 
10755  ImGuiContext& g = *GImGui;
10756  const ImGuiStyle& style = g.Style;
10757 
10758  IM_ASSERT(data_type >= 0 && data_type < ImGuiDataType_COUNT);
10759  if (format == NULL)
10760  format = GDataTypeInfo[data_type].PrintFmt;
10761 
10762  char buf[64];
10763  DataTypeFormatString(buf, IM_ARRAYSIZE(buf), data_type, data_ptr, format);
10764 
10765  bool value_changed = false;
10766  if ((extra_flags & (ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsScientific)) == 0)
10767  extra_flags |= ImGuiInputTextFlags_CharsDecimal;
10768  extra_flags |= ImGuiInputTextFlags_AutoSelectAll;
10769 
10770  if (step != NULL)
10771  {
10772  const float button_size = GetFrameHeight();
10773 
10774  BeginGroup(); // The only purpose of the group here is to allow the caller to query item data e.g. IsItemActive()
10775  PushID(label);
10776  PushItemWidth(ImMax(1.0f, CalcItemWidth() - (button_size + style.ItemInnerSpacing.x) * 2));
10777  if (InputText("", buf, IM_ARRAYSIZE(buf), extra_flags)) // PushId(label) + "" gives us the expected ID from outside point of view
10778  value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialText.Data, data_type, data_ptr, format);
10779  PopItemWidth();
10780 
10781  // Step buttons
10782  SameLine(0, style.ItemInnerSpacing.x);
10783  if (ButtonEx("-", ImVec2(button_size, button_size), ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups))
10784  {
10785  DataTypeApplyOp(data_type, '-', data_ptr, data_ptr, g.IO.KeyCtrl && step_fast ? step_fast : step);
10786  value_changed = true;
10787  }
10788  SameLine(0, style.ItemInnerSpacing.x);
10789  if (ButtonEx("+", ImVec2(button_size, button_size), ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups))
10790  {
10791  DataTypeApplyOp(data_type, '+', data_ptr, data_ptr, g.IO.KeyCtrl && step_fast ? step_fast : step);
10792  value_changed = true;
10793  }
10794  SameLine(0, style.ItemInnerSpacing.x);
10795  TextUnformatted(label, FindRenderedTextEnd(label));
10796 
10797  PopID();
10798  EndGroup();
10799  }
10800  else
10801  {
10802  if (InputText(label, buf, IM_ARRAYSIZE(buf), extra_flags))
10803  value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialText.Data, data_type, data_ptr, format);
10804  }
10805 
10806  return value_changed;
10807 }
10808 
10809 bool ImGui::InputFloat(const char* label, float* v, float step, float step_fast, const char* format, ImGuiInputTextFlags extra_flags)
10810 {
10811  extra_flags |= ImGuiInputTextFlags_CharsScientific;
10812  return InputScalar(label, ImGuiDataType_Float, (void*)v, (void*)(step>0.0f ? &step : NULL), (void*)(step_fast>0.0f ? &step_fast : NULL), format, extra_flags);
10813 }
10814 
10815 bool ImGui::InputDouble(const char* label, double* v, double step, double step_fast, const char* format, ImGuiInputTextFlags extra_flags)
10816 {
10817  extra_flags |= ImGuiInputTextFlags_CharsScientific;
10818  return InputScalar(label, ImGuiDataType_Double, (void*)v, (void*)(step>0.0 ? &step : NULL), (void*)(step_fast>0.0 ? &step_fast : NULL), format, extra_flags);
10819 }
10820 
10821 bool ImGui::InputInt(const char* label, int* v, int step, int step_fast, ImGuiInputTextFlags extra_flags)
10822 {
10823  // Hexadecimal input provided as a convenience but the flag name is awkward. Typically you'd use InputText() to parse your own data, if you want to handle prefixes.
10824  const char* format = (extra_flags & ImGuiInputTextFlags_CharsHexadecimal) ? "%08X" : "%d";
10825  return InputScalar(label, ImGuiDataType_S32, (void*)v, (void*)(step>0 ? &step : NULL), (void*)(step_fast>0 ? &step_fast : NULL), format, extra_flags);
10826 }
10827 
10828 bool ImGui::InputScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* step, const void* step_fast, const char* format, ImGuiInputTextFlags extra_flags)
10829 {
10830  ImGuiWindow* window = GetCurrentWindow();
10831  if (window->SkipItems)
10832  return false;
10833 
10834  ImGuiContext& g = *GImGui;
10835  bool value_changed = false;
10836  BeginGroup();
10837  PushID(label);
10838  PushMultiItemsWidths(components);
10839  size_t type_size = GDataTypeInfo[data_type].Size;
10840  for (int i = 0; i < components; i++)
10841  {
10842  PushID(i);
10843  value_changed |= InputScalar("##v", data_type, v, step, step_fast, format, extra_flags);
10845  PopID();
10846  PopItemWidth();
10847  v = (void*)((char*)v + type_size);
10848  }
10849  PopID();
10850 
10851  TextUnformatted(label, FindRenderedTextEnd(label));
10852  EndGroup();
10853 
10854  return value_changed;
10855 }
10856 
10857 bool ImGui::InputFloat2(const char* label, float v[2], const char* format, ImGuiInputTextFlags extra_flags)
10858 {
10859  return InputScalarN(label, ImGuiDataType_Float, v, 2, NULL, NULL, format, extra_flags);
10860 }
10861 
10862 bool ImGui::InputFloat3(const char* label, float v[3], const char* format, ImGuiInputTextFlags extra_flags)
10863 {
10864  return InputScalarN(label, ImGuiDataType_Float, v, 3, NULL, NULL, format, extra_flags);
10865 }
10866 
10867 bool ImGui::InputFloat4(const char* label, float v[4], const char* format, ImGuiInputTextFlags extra_flags)
10868 {
10869  return InputScalarN(label, ImGuiDataType_Float, v, 4, NULL, NULL, format, extra_flags);
10870 }
10871 
10872 // Prefer using "const char* format" directly, which is more flexible and consistent with other API.
10873 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
10874 bool ImGui::InputFloat(const char* label, float* v, float step, float step_fast, int decimal_precision, ImGuiInputTextFlags extra_flags)
10875 {
10876  char format[16] = "%f";
10877  if (decimal_precision >= 0)
10878  ImFormatString(format, IM_ARRAYSIZE(format), "%%.%df", decimal_precision);
10879  return InputFloat(label, v, step, step_fast, format, extra_flags);
10880 }
10881 
10882 bool ImGui::InputFloat2(const char* label, float v[2], int decimal_precision, ImGuiInputTextFlags extra_flags)
10883 {
10884  char format[16] = "%f";
10885  if (decimal_precision >= 0)
10886  ImFormatString(format, IM_ARRAYSIZE(format), "%%.%df", decimal_precision);
10887  return InputScalarN(label, ImGuiDataType_Float, v, 2, NULL, NULL, format, extra_flags);
10888 }
10889 
10890 bool ImGui::InputFloat3(const char* label, float v[3], int decimal_precision, ImGuiInputTextFlags extra_flags)
10891 {
10892  char format[16] = "%f";
10893  if (decimal_precision >= 0)
10894  ImFormatString(format, IM_ARRAYSIZE(format), "%%.%df", decimal_precision);
10895  return InputScalarN(label, ImGuiDataType_Float, v, 3, NULL, NULL, format, extra_flags);
10896 }
10897 
10898 bool ImGui::InputFloat4(const char* label, float v[4], int decimal_precision, ImGuiInputTextFlags extra_flags)
10899 {
10900  char format[16] = "%f";
10901  if (decimal_precision >= 0)
10902  ImFormatString(format, IM_ARRAYSIZE(format), "%%.%df", decimal_precision);
10903  return InputScalarN(label, ImGuiDataType_Float, v, 4, NULL, NULL, format, extra_flags);
10904 }
10905 #endif // IMGUI_DISABLE_OBSOLETE_FUNCTIONS
10906 
10907 bool ImGui::InputInt2(const char* label, int v[2], ImGuiInputTextFlags extra_flags)
10908 {
10909  return InputScalarN(label, ImGuiDataType_S32, v, 2, NULL, NULL, "%d", extra_flags);
10910 }
10911 
10912 bool ImGui::InputInt3(const char* label, int v[3], ImGuiInputTextFlags extra_flags)
10913 {
10914  return InputScalarN(label, ImGuiDataType_S32, v, 3, NULL, NULL, "%d", extra_flags);
10915 }
10916 
10917 bool ImGui::InputInt4(const char* label, int v[4], ImGuiInputTextFlags extra_flags)
10918 {
10919  return InputScalarN(label, ImGuiDataType_S32, v, 4, NULL, NULL, "%d", extra_flags);
10920 }
10921 
10922 static float CalcMaxPopupHeightFromItemCount(int items_count)
10923 {
10924  ImGuiContext& g = *GImGui;
10925  if (items_count <= 0)
10926  return FLT_MAX;
10927  return (g.FontSize + g.Style.ItemSpacing.y) * items_count - g.Style.ItemSpacing.y + (g.Style.WindowPadding.y * 2);
10928 }
10929 
10930 bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboFlags flags)
10931 {
10932  // Always consume the SetNextWindowSizeConstraint() call in our early return paths
10933  ImGuiContext& g = *GImGui;
10934  ImGuiCond backup_next_window_size_constraint = g.NextWindowData.SizeConstraintCond;
10936 
10937  ImGuiWindow* window = GetCurrentWindow();
10938  if (window->SkipItems)
10939  return false;
10940 
10942 
10943  const ImGuiStyle& style = g.Style;
10944  const ImGuiID id = window->GetID(label);
10945 
10946  const float arrow_size = (flags & ImGuiComboFlags_NoArrowButton) ? 0.0f : GetFrameHeight();
10947  const ImVec2 label_size = CalcTextSize(label, NULL, true);
10948  const float w = (flags & ImGuiComboFlags_NoPreview) ? arrow_size : CalcItemWidth();
10949  const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f));
10950  const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
10951  ItemSize(total_bb, style.FramePadding.y);
10952  if (!ItemAdd(total_bb, id, &frame_bb))
10953  return false;
10954 
10955  bool hovered, held;
10956  bool pressed = ButtonBehavior(frame_bb, id, &hovered, &held);
10957  bool popup_open = IsPopupOpen(id);
10958 
10959  const ImRect value_bb(frame_bb.Min, frame_bb.Max - ImVec2(arrow_size, 0.0f));
10960  const ImU32 frame_col = GetColorU32(hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);
10961  RenderNavHighlight(frame_bb, id);
10962  if (!(flags & ImGuiComboFlags_NoPreview))
10963  window->DrawList->AddRectFilled(frame_bb.Min, ImVec2(frame_bb.Max.x - arrow_size, frame_bb.Max.y), frame_col, style.FrameRounding, ImDrawCornerFlags_Left);
10964  if (!(flags & ImGuiComboFlags_NoArrowButton))
10965  {
10966  window->DrawList->AddRectFilled(ImVec2(frame_bb.Max.x - arrow_size, frame_bb.Min.y), frame_bb.Max, GetColorU32((popup_open || hovered) ? ImGuiCol_ButtonHovered : ImGuiCol_Button), style.FrameRounding, (w <= arrow_size) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Right);
10967  RenderArrow(ImVec2(frame_bb.Max.x - arrow_size + style.FramePadding.y, frame_bb.Min.y + style.FramePadding.y), ImGuiDir_Down);
10968  }
10969  RenderFrameBorder(frame_bb.Min, frame_bb.Max, style.FrameRounding);
10970  if (preview_value != NULL && !(flags & ImGuiComboFlags_NoPreview))
10971  RenderTextClipped(frame_bb.Min + style.FramePadding, value_bb.Max, preview_value, NULL, NULL, ImVec2(0.0f,0.0f));
10972  if (label_size.x > 0)
10973  RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
10974 
10975  if ((pressed || g.NavActivateId == id) && !popup_open)
10976  {
10977  if (window->DC.NavLayerCurrent == 0)
10978  window->NavLastIds[0] = id;
10979  OpenPopupEx(id);
10980  popup_open = true;
10981  }
10982 
10983  if (!popup_open)
10984  return false;
10985 
10986  if (backup_next_window_size_constraint)
10987  {
10988  g.NextWindowData.SizeConstraintCond = backup_next_window_size_constraint;
10990  }
10991  else
10992  {
10993  if ((flags & ImGuiComboFlags_HeightMask_) == 0)
10995  IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiComboFlags_HeightMask_)); // Only one
10996  int popup_max_height_in_items = -1;
10997  if (flags & ImGuiComboFlags_HeightRegular) popup_max_height_in_items = 8;
10998  else if (flags & ImGuiComboFlags_HeightSmall) popup_max_height_in_items = 4;
10999  else if (flags & ImGuiComboFlags_HeightLarge) popup_max_height_in_items = 20;
11000  SetNextWindowSizeConstraints(ImVec2(w, 0.0f), ImVec2(FLT_MAX, CalcMaxPopupHeightFromItemCount(popup_max_height_in_items)));
11001  }
11002 
11003  char name[16];
11004  ImFormatString(name, IM_ARRAYSIZE(name), "##Combo_%02d", g.CurrentPopupStack.Size); // Recycle windows based on depth
11005 
11006  // Peak into expected window size so we can position it
11007  if (ImGuiWindow* popup_window = FindWindowByName(name))
11008  if (popup_window->WasActive)
11009  {
11010  ImVec2 size_contents = CalcSizeContents(popup_window);
11011  ImVec2 size_expected = CalcSizeAfterConstraint(popup_window, CalcSizeAutoFit(popup_window, size_contents));
11012  if (flags & ImGuiComboFlags_PopupAlignLeft)
11013  popup_window->AutoPosLastDirection = ImGuiDir_Left;
11014  ImRect r_outer = FindAllowedExtentRectForWindow(popup_window);
11015  ImVec2 pos = FindBestWindowPosForPopupEx(frame_bb.GetBL(), size_expected, &popup_window->AutoPosLastDirection, r_outer, frame_bb, ImGuiPopupPositionPolicy_ComboBox);
11016  SetNextWindowPos(pos);
11017  }
11018 
11019  // Horizontally align ourselves with the framed text
11021 
11022  ImGuiWindowFlags window_flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_Popup | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings;
11023  if (!Begin(name, NULL, window_flags))
11024  {
11025  EndPopup();
11026  PopStyleVar();
11027  IM_ASSERT(0); // This should never happen as we tested for IsPopupOpen() above
11028  return false;
11029  }
11030  return true;
11031 }
11032 
11034 {
11035  EndPopup();
11036  PopStyleVar();
11037 }
11038 
11039 // Old API, prefer using BeginCombo() nowadays if you can.
11040 bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(void*, int, const char**), void* data, int items_count, int popup_max_height_in_items)
11041 {
11042  ImGuiContext& g = *GImGui;
11043 
11044  const char* preview_text = NULL;
11045  if (*current_item >= 0 && *current_item < items_count)
11046  items_getter(data, *current_item, &preview_text);
11047 
11048  // The old Combo() API exposed "popup_max_height_in_items". The new more general BeginCombo() API doesn't, so we emulate it here.
11049  if (popup_max_height_in_items != -1 && !g.NextWindowData.SizeConstraintCond)
11050  {
11051  float popup_max_height = CalcMaxPopupHeightFromItemCount(popup_max_height_in_items);
11052  SetNextWindowSizeConstraints(ImVec2(0,0), ImVec2(FLT_MAX, popup_max_height));
11053  }
11054 
11055  if (!BeginCombo(label, preview_text, 0))
11056  return false;
11057 
11058  // Display items
11059  // FIXME-OPT: Use clipper (but we need to disable it on the appearing frame to make sure our call to SetItemDefaultFocus() is processed)
11060  bool value_changed = false;
11061  for (int i = 0; i < items_count; i++)
11062  {
11063  PushID((void*)(intptr_t)i);
11064  const bool item_selected = (i == *current_item);
11065  const char* item_text;
11066  if (!items_getter(data, i, &item_text))
11067  item_text = "*Unknown item*";
11068  if (Selectable(item_text, item_selected))
11069  {
11070  value_changed = true;
11071  *current_item = i;
11072  }
11073  if (item_selected)
11075  PopID();
11076  }
11077 
11078  EndCombo();
11079  return value_changed;
11080 }
11081 
11082 static bool Items_ArrayGetter(void* data, int idx, const char** out_text)
11083 {
11084  const char* const* items = (const char* const*)data;
11085  if (out_text)
11086  *out_text = items[idx];
11087  return true;
11088 }
11089 
11090 static bool Items_SingleStringGetter(void* data, int idx, const char** out_text)
11091 {
11092  // FIXME-OPT: we could pre-compute the indices to fasten this. But only 1 active combo means the waste is limited.
11093  const char* items_separated_by_zeros = (const char*)data;
11094  int items_count = 0;
11095  const char* p = items_separated_by_zeros;
11096  while (*p)
11097  {
11098  if (idx == items_count)
11099  break;
11100  p += strlen(p) + 1;
11101  items_count++;
11102  }
11103  if (!*p)
11104  return false;
11105  if (out_text)
11106  *out_text = p;
11107  return true;
11108 }
11109 
11110 // Combo box helper allowing to pass an array of strings.
11111 bool ImGui::Combo(const char* label, int* current_item, const char* const items[], int items_count, int height_in_items)
11112 {
11113  const bool value_changed = Combo(label, current_item, Items_ArrayGetter, (void*)items, items_count, height_in_items);
11114  return value_changed;
11115 }
11116 
11117 // Combo box helper allowing to pass all items in a single string.
11118 bool ImGui::Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int height_in_items)
11119 {
11120  int items_count = 0;
11121  const char* p = items_separated_by_zeros; // FIXME-OPT: Avoid computing this, or at least only when combo is open
11122  while (*p)
11123  {
11124  p += strlen(p) + 1;
11125  items_count++;
11126  }
11127  bool value_changed = Combo(label, current_item, Items_SingleStringGetter, (void*)items_separated_by_zeros, items_count, height_in_items);
11128  return value_changed;
11129 }
11130 
11131 // Tip: pass an empty label (e.g. "##dummy") then you can use the space to draw other text or image.
11132 // But you need to make sure the ID is unique, e.g. enclose calls in PushID/PopID.
11133 bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags flags, const ImVec2& size_arg)
11134 {
11135  ImGuiWindow* window = GetCurrentWindow();
11136  if (window->SkipItems)
11137  return false;
11138 
11139  ImGuiContext& g = *GImGui;
11140  const ImGuiStyle& style = g.Style;
11141 
11142  if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsSet) // FIXME-OPT: Avoid if vertically clipped.
11143  PopClipRect();
11144 
11145  ImGuiID id = window->GetID(label);
11146  ImVec2 label_size = CalcTextSize(label, NULL, true);
11147  ImVec2 size(size_arg.x != 0.0f ? size_arg.x : label_size.x, size_arg.y != 0.0f ? size_arg.y : label_size.y);
11148  ImVec2 pos = window->DC.CursorPos;
11149  pos.y += window->DC.CurrentLineTextBaseOffset;
11150  ImRect bb(pos, pos + size);
11151  ItemSize(bb);
11152 
11153  // Fill horizontal space.
11154  ImVec2 window_padding = window->WindowPadding;
11156  float w_draw = ImMax(label_size.x, window->Pos.x + max_x - window_padding.x - window->DC.CursorPos.x);
11157  ImVec2 size_draw((size_arg.x != 0 && !(flags & ImGuiSelectableFlags_DrawFillAvailWidth)) ? size_arg.x : w_draw, size_arg.y != 0.0f ? size_arg.y : size.y);
11158  ImRect bb_with_spacing(pos, pos + size_draw);
11159  if (size_arg.x == 0.0f || (flags & ImGuiSelectableFlags_DrawFillAvailWidth))
11160  bb_with_spacing.Max.x += window_padding.x;
11161 
11162  // Selectables are tightly packed together, we extend the box to cover spacing between selectable.
11163  float spacing_L = (float)(int)(style.ItemSpacing.x * 0.5f);
11164  float spacing_U = (float)(int)(style.ItemSpacing.y * 0.5f);
11165  float spacing_R = style.ItemSpacing.x - spacing_L;
11166  float spacing_D = style.ItemSpacing.y - spacing_U;
11167  bb_with_spacing.Min.x -= spacing_L;
11168  bb_with_spacing.Min.y -= spacing_U;
11169  bb_with_spacing.Max.x += spacing_R;
11170  bb_with_spacing.Max.y += spacing_D;
11171  if (!ItemAdd(bb_with_spacing, (flags & ImGuiSelectableFlags_Disabled) ? 0 : id))
11172  {
11173  if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsSet)
11175  return false;
11176  }
11177 
11178  ImGuiButtonFlags button_flags = 0;
11181  if (flags & ImGuiSelectableFlags_Disabled) button_flags |= ImGuiButtonFlags_Disabled;
11183  bool hovered, held;
11184  bool pressed = ButtonBehavior(bb_with_spacing, id, &hovered, &held, button_flags);
11185  if (flags & ImGuiSelectableFlags_Disabled)
11186  selected = false;
11187 
11188  // Hovering selectable with mouse updates NavId accordingly so navigation can be resumed with gamepad/keyboard (this doesn't happen on most widgets)
11189  if (pressed || hovered)
11190  if (!g.NavDisableMouseHover && g.NavWindow == window && g.NavLayer == window->DC.NavLayerCurrent)
11191  {
11192  g.NavDisableHighlight = true;
11193  SetNavID(id, window->DC.NavLayerCurrent);
11194  }
11195 
11196  // Render
11197  if (hovered || selected)
11198  {
11199  const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
11200  RenderFrame(bb_with_spacing.Min, bb_with_spacing.Max, col, false, 0.0f);
11202  }
11203 
11204  if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsSet)
11205  {
11207  bb_with_spacing.Max.x -= (GetContentRegionMax().x - max_x);
11208  }
11209 
11210  if (flags & ImGuiSelectableFlags_Disabled) PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]);
11211  RenderTextClipped(bb.Min, bb_with_spacing.Max, label, NULL, &label_size, ImVec2(0.0f,0.0f));
11212  if (flags & ImGuiSelectableFlags_Disabled) PopStyleColor();
11213 
11214  // Automatically close popups
11217  return pressed;
11218 }
11219 
11220 bool ImGui::Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags, const ImVec2& size_arg)
11221 {
11222  if (Selectable(label, *p_selected, flags, size_arg))
11223  {
11224  *p_selected = !*p_selected;
11225  return true;
11226  }
11227  return false;
11228 }
11229 
11230 // Helper to calculate the size of a listbox and display a label on the right.
11231 // Tip: To have a list filling the entire window width, PushItemWidth(-1) and pass an empty label "##empty"
11232 bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg)
11233 {
11234  ImGuiWindow* window = GetCurrentWindow();
11235  if (window->SkipItems)
11236  return false;
11237 
11238  const ImGuiStyle& style = GetStyle();
11239  const ImGuiID id = GetID(label);
11240  const ImVec2 label_size = CalcTextSize(label, NULL, true);
11241 
11242  // Size default to hold ~7 items. Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar.
11243  ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), GetTextLineHeightWithSpacing() * 7.4f + style.ItemSpacing.y);
11244  ImVec2 frame_size = ImVec2(size.x, ImMax(size.y, label_size.y));
11245  ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size);
11246  ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
11247  window->DC.LastItemRect = bb; // Forward storage for ListBoxFooter.. dodgy.
11248 
11249  BeginGroup();
11250  if (label_size.x > 0)
11251  RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
11252 
11253  BeginChildFrame(id, frame_bb.GetSize());
11254  return true;
11255 }
11256 
11257 bool ImGui::ListBoxHeader(const char* label, int items_count, int height_in_items)
11258 {
11259  // Size default to hold ~7 items. Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar.
11260  // We don't add +0.40f if items_count <= height_in_items. It is slightly dodgy, because it means a dynamic list of items will make the widget resize occasionally when it crosses that size.
11261  // I am expecting that someone will come and complain about this behavior in a remote future, then we can advise on a better solution.
11262  if (height_in_items < 0)
11263  height_in_items = ImMin(items_count, 7);
11264  float height_in_items_f = height_in_items < items_count ? (height_in_items + 0.40f) : (height_in_items + 0.00f);
11265 
11266  // We include ItemSpacing.y so that a list sized for the exact number of items doesn't make a scrollbar appears. We could also enforce that by passing a flag to BeginChild().
11267  ImVec2 size;
11268  size.x = 0.0f;
11269  size.y = GetTextLineHeightWithSpacing() * height_in_items_f + GetStyle().ItemSpacing.y;
11270  return ListBoxHeader(label, size);
11271 }
11272 
11274 {
11275  ImGuiWindow* parent_window = GetCurrentWindow()->ParentWindow;
11276  const ImRect bb = parent_window->DC.LastItemRect;
11277  const ImGuiStyle& style = GetStyle();
11278 
11279  EndChildFrame();
11280 
11281  // Redeclare item size so that it includes the label (we have stored the full size in LastItemRect)
11282  // We call SameLine() to restore DC.CurrentLine* data
11283  SameLine();
11284  parent_window->DC.CursorPos = bb.Min;
11285  ItemSize(bb, style.FramePadding.y);
11286  EndGroup();
11287 }
11288 
11289 bool ImGui::ListBox(const char* label, int* current_item, const char* const items[], int items_count, int height_items)
11290 {
11291  const bool value_changed = ListBox(label, current_item, Items_ArrayGetter, (void*)items, items_count, height_items);
11292  return value_changed;
11293 }
11294 
11295 bool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(void*, int, const char**), void* data, int items_count, int height_in_items)
11296 {
11297  if (!ListBoxHeader(label, items_count, height_in_items))
11298  return false;
11299 
11300  // Assume all items have even height (= 1 line of text). If you need items of different or variable sizes you can create a custom version of ListBox() in your code without using the clipper.
11301  bool value_changed = false;
11302  ImGuiListClipper clipper(items_count, GetTextLineHeightWithSpacing()); // We know exactly our line height here so we pass it as a minor optimization, but generally you don't need to.
11303  while (clipper.Step())
11304  for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
11305  {
11306  const bool item_selected = (i == *current_item);
11307  const char* item_text;
11308  if (!items_getter(data, i, &item_text))
11309  item_text = "*Unknown item*";
11310 
11311  PushID(i);
11312  if (Selectable(item_text, item_selected))
11313  {
11314  *current_item = i;
11315  value_changed = true;
11316  }
11317  if (item_selected)
11319  PopID();
11320  }
11321  ListBoxFooter();
11322  return value_changed;
11323 }
11324 
11325 bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, bool enabled)
11326 {
11327  ImGuiWindow* window = GetCurrentWindow();
11328  if (window->SkipItems)
11329  return false;
11330 
11331  ImGuiContext& g = *GImGui;
11332  ImGuiStyle& style = g.Style;
11333  ImVec2 pos = window->DC.CursorPos;
11334  ImVec2 label_size = CalcTextSize(label, NULL, true);
11335 
11337  bool pressed;
11338  if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
11339  {
11340  // Mimic the exact layout spacing of BeginMenu() to allow MenuItem() inside a menu bar, which is a little misleading but may be useful
11341  // Note that in this situation we render neither the shortcut neither the selected tick mark
11342  float w = label_size.x;
11343  window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * 0.5f);
11345  pressed = Selectable(label, false, flags, ImVec2(w, 0.0f));
11346  PopStyleVar();
11347  window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar().
11348  }
11349  else
11350  {
11351  ImVec2 shortcut_size = shortcut ? CalcTextSize(shortcut, NULL) : ImVec2(0.0f, 0.0f);
11352  float w = window->MenuColumns.DeclColumns(label_size.x, shortcut_size.x, (float)(int)(g.FontSize * 1.20f)); // Feedback for next frame
11353  float extra_w = ImMax(0.0f, GetContentRegionAvail().x - w);
11354  pressed = Selectable(label, false, flags | ImGuiSelectableFlags_DrawFillAvailWidth, ImVec2(w, 0.0f));
11355  if (shortcut_size.x > 0.0f)
11356  {
11358  RenderText(pos + ImVec2(window->MenuColumns.Pos[1] + extra_w, 0.0f), shortcut, NULL, false);
11359  PopStyleColor();
11360  }
11361  if (selected)
11362  RenderCheckMark(pos + ImVec2(window->MenuColumns.Pos[2] + extra_w + g.FontSize * 0.40f, g.FontSize * 0.134f * 0.5f), GetColorU32(enabled ? ImGuiCol_Text : ImGuiCol_TextDisabled), g.FontSize * 0.866f);
11363  }
11364  return pressed;
11365 }
11366 
11367 bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled)
11368 {
11369  if (MenuItem(label, shortcut, p_selected ? *p_selected : false, enabled))
11370  {
11371  if (p_selected)
11372  *p_selected = !*p_selected;
11373  return true;
11374  }
11375  return false;
11376 }
11377 
11378 // For the main menu bar, which cannot be moved, we honor g.Style.DisplaySafeAreaPadding to ensure text can be visible on a TV set.
11380 {
11381  ImGuiContext& g = *GImGui;
11383  SetNextWindowPos(ImVec2(0.0f, 0.0f));
11387  ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar;
11388  bool is_open = Begin("##MainMenuBar", NULL, window_flags) && BeginMenuBar();
11389  g.NextWindowData.MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f);
11390  if (!is_open)
11391  {
11392  End();
11393  PopStyleVar(2);
11394  return false;
11395  }
11396  return true;
11397 }
11398 
11400 {
11401  EndMenuBar();
11402 
11403  // When the user has left the menu layer (typically: closed menus through activation of an item), we restore focus to the previous window
11404  ImGuiContext& g = *GImGui;
11405  if (g.CurrentWindow == g.NavWindow && g.NavLayer == 0)
11406  FocusFrontMostActiveWindow(g.NavWindow);
11407 
11408  End();
11409  PopStyleVar(2);
11410 }
11411 
11413 {
11414  ImGuiWindow* window = GetCurrentWindow();
11415  if (window->SkipItems)
11416  return false;
11417  if (!(window->Flags & ImGuiWindowFlags_MenuBar))
11418  return false;
11419 
11420  IM_ASSERT(!window->DC.MenuBarAppending);
11421  BeginGroup(); // Save position
11422  PushID("##menubar");
11423 
11424  // We don't clip with current window clipping rectangle as it is already set to the area below. However we clip with window full rect.
11425  // We remove 1 worth of rounding to Max.x to that text in long menus and small windows don't tend to display over the lower-right rounded area, which looks particularly glitchy.
11426  ImRect bar_rect = window->MenuBarRect();
11427  ImRect clip_rect(ImFloor(bar_rect.Min.x + 0.5f), ImFloor(bar_rect.Min.y + window->WindowBorderSize + 0.5f), ImFloor(ImMax(bar_rect.Min.x, bar_rect.Max.x - window->WindowRounding) + 0.5f), ImFloor(bar_rect.Max.y + 0.5f));
11428  clip_rect.ClipWith(window->OuterRectClipped);
11429  PushClipRect(clip_rect.Min, clip_rect.Max, false);
11430 
11431  window->DC.CursorPos = ImVec2(bar_rect.Min.x + window->DC.MenuBarOffset.x, bar_rect.Min.y + window->DC.MenuBarOffset.y);
11433  window->DC.NavLayerCurrent++;
11434  window->DC.NavLayerCurrentMask <<= 1;
11435  window->DC.MenuBarAppending = true;
11437  return true;
11438 }
11439 
11441 {
11442  ImGuiWindow* window = GetCurrentWindow();
11443  if (window->SkipItems)
11444  return;
11445  ImGuiContext& g = *GImGui;
11446 
11447  // Nav: When a move request within one of our child menu failed, capture the request to navigate among our siblings.
11448  if (NavMoveRequestButNoResultYet() && (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) && (g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu))
11449  {
11450  ImGuiWindow* nav_earliest_child = g.NavWindow;
11451  while (nav_earliest_child->ParentWindow && (nav_earliest_child->ParentWindow->Flags & ImGuiWindowFlags_ChildMenu))
11452  nav_earliest_child = nav_earliest_child->ParentWindow;
11453  if (nav_earliest_child->ParentWindow == window && nav_earliest_child->DC.ParentLayoutType == ImGuiLayoutType_Horizontal && g.NavMoveRequestForward == ImGuiNavForward_None)
11454  {
11455  // To do so we claim focus back, restore NavId and then process the movement request for yet another frame.
11456  // This involve a one-frame delay which isn't very problematic in this situation. We could remove it by scoring in advance for multiple window (probably not worth the hassle/cost)
11457  IM_ASSERT(window->DC.NavLayerActiveMaskNext & 0x02); // Sanity check
11458  FocusWindow(window);
11459  SetNavIDWithRectRel(window->NavLastIds[1], 1, window->NavRectRel[1]);
11460  g.NavLayer = 1;
11461  g.NavDisableHighlight = true; // Hide highlight for the current frame so we don't see the intermediary selection.
11464  }
11465  }
11466 
11468  IM_ASSERT(window->DC.MenuBarAppending);
11469  PopClipRect();
11470  PopID();
11471  window->DC.MenuBarOffset.x = window->DC.CursorPos.x - window->MenuBarRect().Min.x; // Save horizontal position so next append can reuse it. This is kinda equivalent to a per-layer CursorPos.
11472  window->DC.GroupStack.back().AdvanceCursor = false;
11473  EndGroup();
11475  window->DC.NavLayerCurrent--;
11476  window->DC.NavLayerCurrentMask >>= 1;
11477  window->DC.MenuBarAppending = false;
11478 }
11479 
11480 bool ImGui::BeginMenu(const char* label, bool enabled)
11481 {
11482  ImGuiWindow* window = GetCurrentWindow();
11483  if (window->SkipItems)
11484  return false;
11485 
11486  ImGuiContext& g = *GImGui;
11487  const ImGuiStyle& style = g.Style;
11488  const ImGuiID id = window->GetID(label);
11489 
11490  ImVec2 label_size = CalcTextSize(label, NULL, true);
11491 
11492  bool pressed;
11493  bool menu_is_open = IsPopupOpen(id);
11494  bool menuset_is_open = !(window->Flags & ImGuiWindowFlags_Popup) && (g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].OpenParentId == window->IDStack.back());
11495  ImGuiWindow* backed_nav_window = g.NavWindow;
11496  if (menuset_is_open)
11497  g.NavWindow = window; // Odd hack to allow hovering across menus of a same menu-set (otherwise we wouldn't be able to hover parent)
11498 
11499  // The reference position stored in popup_pos will be used by Begin() to find a suitable position for the child menu (using FindBestWindowPosForPopup).
11500  ImVec2 popup_pos, pos = window->DC.CursorPos;
11501  if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
11502  {
11503  // Menu inside an horizontal menu bar
11504  // Selectable extend their highlight by half ItemSpacing in each direction.
11505  // For ChildMenu, the popup position will be overwritten by the call to FindBestWindowPosForPopup() in Begin()
11506  popup_pos = ImVec2(pos.x - window->WindowPadding.x, pos.y - style.FramePadding.y + window->MenuBarHeight());
11507  window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * 0.5f);
11509  float w = label_size.x;
11510  pressed = Selectable(label, menu_is_open, ImGuiSelectableFlags_Menu | ImGuiSelectableFlags_DontClosePopups | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(w, 0.0f));
11511  PopStyleVar();
11512  window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar().
11513  }
11514  else
11515  {
11516  // Menu inside a menu
11517  popup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y);
11518  float w = window->MenuColumns.DeclColumns(label_size.x, 0.0f, (float)(int)(g.FontSize * 1.20f)); // Feedback to next frame
11519  float extra_w = ImMax(0.0f, GetContentRegionAvail().x - w);
11522  RenderArrow(pos + ImVec2(window->MenuColumns.Pos[2] + extra_w + g.FontSize * 0.30f, 0.0f), ImGuiDir_Right);
11523  if (!enabled) PopStyleColor();
11524  }
11525 
11526  const bool hovered = enabled && ItemHoverable(window->DC.LastItemRect, id);
11527  if (menuset_is_open)
11528  g.NavWindow = backed_nav_window;
11529 
11530  bool want_open = false, want_close = false;
11531  if (window->DC.LayoutType == ImGuiLayoutType_Vertical) // (window->Flags & (ImGuiWindowFlags_Popup|ImGuiWindowFlags_ChildMenu))
11532  {
11533  // Implement http://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown to avoid using timers, so menus feels more reactive.
11534  bool moving_within_opened_triangle = false;
11535  if (g.HoveredWindow == window && g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].ParentWindow == window && !(window->Flags & ImGuiWindowFlags_MenuBar))
11536  {
11537  if (ImGuiWindow* next_window = g.OpenPopupStack[g.CurrentPopupStack.Size].Window)
11538  {
11539  ImRect next_window_rect = next_window->Rect();
11540  ImVec2 ta = g.IO.MousePos - g.IO.MouseDelta;
11541  ImVec2 tb = (window->Pos.x < next_window->Pos.x) ? next_window_rect.GetTL() : next_window_rect.GetTR();
11542  ImVec2 tc = (window->Pos.x < next_window->Pos.x) ? next_window_rect.GetBL() : next_window_rect.GetBR();
11543  float extra = ImClamp(ImFabs(ta.x - tb.x) * 0.30f, 5.0f, 30.0f); // add a bit of extra slack.
11544  ta.x += (window->Pos.x < next_window->Pos.x) ? -0.5f : +0.5f; // to avoid numerical issues
11545  tb.y = ta.y + ImMax((tb.y - extra) - ta.y, -100.0f); // triangle is maximum 200 high to limit the slope and the bias toward large sub-menus // FIXME: Multiply by fb_scale?
11546  tc.y = ta.y + ImMin((tc.y + extra) - ta.y, +100.0f);
11547  moving_within_opened_triangle = ImTriangleContainsPoint(ta, tb, tc, g.IO.MousePos);
11548  //window->DrawList->PushClipRectFullScreen(); window->DrawList->AddTriangleFilled(ta, tb, tc, moving_within_opened_triangle ? IM_COL32(0,128,0,128) : IM_COL32(128,0,0,128)); window->DrawList->PopClipRect(); // Debug
11549  }
11550  }
11551 
11552  want_close = (menu_is_open && !hovered && g.HoveredWindow == window && g.HoveredIdPreviousFrame != 0 && g.HoveredIdPreviousFrame != id && !moving_within_opened_triangle);
11553  want_open = (!menu_is_open && hovered && !moving_within_opened_triangle) || (!menu_is_open && hovered && pressed);
11554 
11555  if (g.NavActivateId == id)
11556  {
11557  want_close = menu_is_open;
11558  want_open = !menu_is_open;
11559  }
11560  if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Right) // Nav-Right to open
11561  {
11562  want_open = true;
11564  }
11565  }
11566  else
11567  {
11568  // Menu bar
11569  if (menu_is_open && pressed && menuset_is_open) // Click an open menu again to close it
11570  {
11571  want_close = true;
11572  want_open = menu_is_open = false;
11573  }
11574  else if (pressed || (hovered && menuset_is_open && !menu_is_open)) // First click to open, then hover to open others
11575  {
11576  want_open = true;
11577  }
11578  else if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Down) // Nav-Down to open
11579  {
11580  want_open = true;
11582  }
11583  }
11584 
11585  if (!enabled) // explicitly close if an open menu becomes disabled, facilitate users code a lot in pattern such as 'if (BeginMenu("options", has_object)) { ..use object.. }'
11586  want_close = true;
11587  if (want_close && IsPopupOpen(id))
11588  ClosePopupToLevel(g.CurrentPopupStack.Size);
11589 
11590  if (!menu_is_open && want_open && g.OpenPopupStack.Size > g.CurrentPopupStack.Size)
11591  {
11592  // Don't recycle same menu level in the same frame, first close the other menu and yield for a frame.
11593  OpenPopup(label);
11594  return false;
11595  }
11596 
11597  menu_is_open |= want_open;
11598  if (want_open)
11599  OpenPopup(label);
11600 
11601  if (menu_is_open)
11602  {
11603  // Sub-menus are ChildWindow so that mouse can be hovering across them (otherwise top-most popup menu would steal focus and not allow hovering on parent menu)
11604  SetNextWindowPos(popup_pos, ImGuiCond_Always);
11606  menu_is_open = BeginPopupEx(id, flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display)
11607  }
11608 
11609  return menu_is_open;
11610 }
11611 
11613 {
11614  // Nav: When a left move request _within our child menu_ failed, close the menu.
11615  // A menu doesn't close itself because EndMenuBar() wants the catch the last Left<>Right inputs.
11616  // However, it means that with the current code, a BeginMenu() from outside another menu or a menu-bar won't be closable with the Left direction.
11617  ImGuiContext& g = *GImGui;
11618  ImGuiWindow* window = g.CurrentWindow;
11619  if (g.NavWindow && g.NavWindow->ParentWindow == window && g.NavMoveDir == ImGuiDir_Left && NavMoveRequestButNoResultYet() && window->DC.LayoutType == ImGuiLayoutType_Vertical)
11620  {
11621  ClosePopupToLevel(g.OpenPopupStack.Size - 1);
11623  }
11624 
11625  EndPopup();
11626 }
11627 
11628 // Note: only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is set.
11629 void ImGui::ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags flags)
11630 {
11631  ImGuiContext& g = *GImGui;
11632 
11633  int cr = IM_F32_TO_INT8_SAT(col[0]), cg = IM_F32_TO_INT8_SAT(col[1]), cb = IM_F32_TO_INT8_SAT(col[2]), ca = (flags & ImGuiColorEditFlags_NoAlpha) ? 255 : IM_F32_TO_INT8_SAT(col[3]);
11634  BeginTooltipEx(0, true);
11635 
11636  const char* text_end = text ? FindRenderedTextEnd(text, NULL) : text;
11637  if (text_end > text)
11638  {
11639  TextUnformatted(text, text_end);
11640  Separator();
11641  }
11642 
11643  ImVec2 sz(g.FontSize * 3 + g.Style.FramePadding.y * 2, g.FontSize * 3 + g.Style.FramePadding.y * 2);
11645  SameLine();
11646  if (flags & ImGuiColorEditFlags_NoAlpha)
11647  Text("#%02X%02X%02X\nR: %d, G: %d, B: %d\n(%.3f, %.3f, %.3f)", cr, cg, cb, cr, cg, cb, col[0], col[1], col[2]);
11648  else
11649  Text("#%02X%02X%02X%02X\nR:%d, G:%d, B:%d, A:%d\n(%.3f, %.3f, %.3f, %.3f)", cr, cg, cb, ca, cr, cg, cb, ca, col[0], col[1], col[2], col[3]);
11650  EndTooltip();
11651 }
11652 
11653 static inline ImU32 ImAlphaBlendColor(ImU32 col_a, ImU32 col_b)
11654 {
11655  float t = ((col_b >> IM_COL32_A_SHIFT) & 0xFF) / 255.f;
11656  int r = ImLerp((int)(col_a >> IM_COL32_R_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_R_SHIFT) & 0xFF, t);
11657  int g = ImLerp((int)(col_a >> IM_COL32_G_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_G_SHIFT) & 0xFF, t);
11658  int b = ImLerp((int)(col_a >> IM_COL32_B_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_B_SHIFT) & 0xFF, t);
11659  return IM_COL32(r, g, b, 0xFF);
11660 }
11661 
11662 // NB: This is rather brittle and will show artifact when rounding this enabled if rounded corners overlap multiple cells. Caller currently responsible for avoiding that.
11663 // I spent a non reasonable amount of time trying to getting this right for ColorButton with rounding+anti-aliasing+ImGuiColorEditFlags_HalfAlphaPreview flag + various grid sizes and offsets, and eventually gave up... probably more reasonable to disable rounding alltogether.
11664 void ImGui::RenderColorRectWithAlphaCheckerboard(ImVec2 p_min, ImVec2 p_max, ImU32 col, float grid_step, ImVec2 grid_off, float rounding, int rounding_corners_flags)
11665 {
11666  ImGuiWindow* window = GetCurrentWindow();
11667  if (((col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT) < 0xFF)
11668  {
11669  ImU32 col_bg1 = GetColorU32(ImAlphaBlendColor(IM_COL32(204,204,204,255), col));
11670  ImU32 col_bg2 = GetColorU32(ImAlphaBlendColor(IM_COL32(128,128,128,255), col));
11671  window->DrawList->AddRectFilled(p_min, p_max, col_bg1, rounding, rounding_corners_flags);
11672 
11673  int yi = 0;
11674  for (float y = p_min.y + grid_off.y; y < p_max.y; y += grid_step, yi++)
11675  {
11676  float y1 = ImClamp(y, p_min.y, p_max.y), y2 = ImMin(y + grid_step, p_max.y);
11677  if (y2 <= y1)
11678  continue;
11679  for (float x = p_min.x + grid_off.x + (yi & 1) * grid_step; x < p_max.x; x += grid_step * 2.0f)
11680  {
11681  float x1 = ImClamp(x, p_min.x, p_max.x), x2 = ImMin(x + grid_step, p_max.x);
11682  if (x2 <= x1)
11683  continue;
11684  int rounding_corners_flags_cell = 0;
11685  if (y1 <= p_min.y) { if (x1 <= p_min.x) rounding_corners_flags_cell |= ImDrawCornerFlags_TopLeft; if (x2 >= p_max.x) rounding_corners_flags_cell |= ImDrawCornerFlags_TopRight; }
11686  if (y2 >= p_max.y) { if (x1 <= p_min.x) rounding_corners_flags_cell |= ImDrawCornerFlags_BotLeft; if (x2 >= p_max.x) rounding_corners_flags_cell |= ImDrawCornerFlags_BotRight; }
11687  rounding_corners_flags_cell &= rounding_corners_flags;
11688  window->DrawList->AddRectFilled(ImVec2(x1,y1), ImVec2(x2,y2), col_bg2, rounding_corners_flags_cell ? rounding : 0.0f, rounding_corners_flags_cell);
11689  }
11690  }
11691  }
11692  else
11693  {
11694  window->DrawList->AddRectFilled(p_min, p_max, col, rounding, rounding_corners_flags);
11695  }
11696 }
11697 
11699 {
11700  ImGuiContext& g = *GImGui;
11701  if ((flags & ImGuiColorEditFlags__InputsMask) == 0)
11703  if ((flags & ImGuiColorEditFlags__DataTypeMask) == 0)
11705  if ((flags & ImGuiColorEditFlags__PickerMask) == 0)
11707  IM_ASSERT(ImIsPowerOfTwo((int)(flags & ImGuiColorEditFlags__InputsMask))); // Check only 1 option is selected
11708  IM_ASSERT(ImIsPowerOfTwo((int)(flags & ImGuiColorEditFlags__DataTypeMask))); // Check only 1 option is selected
11709  IM_ASSERT(ImIsPowerOfTwo((int)(flags & ImGuiColorEditFlags__PickerMask))); // Check only 1 option is selected
11710  g.ColorEditOptions = flags;
11711 }
11712 
11713 // A little colored square. Return true when clicked.
11714 // FIXME: May want to display/ignore the alpha component in the color display? Yet show it in the tooltip.
11715 // 'desc_id' is not called 'label' because we don't display it next to the button, but only in the tooltip.
11716 bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFlags flags, ImVec2 size)
11717 {
11718  ImGuiWindow* window = GetCurrentWindow();
11719  if (window->SkipItems)
11720  return false;
11721 
11722  ImGuiContext& g = *GImGui;
11723  const ImGuiID id = window->GetID(desc_id);
11724  float default_size = GetFrameHeight();
11725  if (size.x == 0.0f)
11726  size.x = default_size;
11727  if (size.y == 0.0f)
11728  size.y = default_size;
11729  const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);
11730  ItemSize(bb, (size.y >= default_size) ? g.Style.FramePadding.y : 0.0f);
11731  if (!ItemAdd(bb, id))
11732  return false;
11733 
11734  bool hovered, held;
11735  bool pressed = ButtonBehavior(bb, id, &hovered, &held);
11736 
11737  if (flags & ImGuiColorEditFlags_NoAlpha)
11739 
11740  ImVec4 col_without_alpha(col.x, col.y, col.z, 1.0f);
11741  float grid_step = ImMin(size.x, size.y) / 2.99f;
11742  float rounding = ImMin(g.Style.FrameRounding, grid_step * 0.5f);
11743  ImRect bb_inner = bb;
11744  float off = -0.75f; // The border (using Col_FrameBg) tends to look off when color is near-opaque and rounding is enabled. This offset seemed like a good middle ground to reduce those artifacts.
11745  bb_inner.Expand(off);
11746  if ((flags & ImGuiColorEditFlags_AlphaPreviewHalf) && col.w < 1.0f)
11747  {
11748  float mid_x = (float)(int)((bb_inner.Min.x + bb_inner.Max.x) * 0.5f + 0.5f);
11749  RenderColorRectWithAlphaCheckerboard(ImVec2(bb_inner.Min.x + grid_step, bb_inner.Min.y), bb_inner.Max, GetColorU32(col), grid_step, ImVec2(-grid_step + off, off), rounding, ImDrawCornerFlags_TopRight| ImDrawCornerFlags_BotRight);
11750  window->DrawList->AddRectFilled(bb_inner.Min, ImVec2(mid_x, bb_inner.Max.y), GetColorU32(col_without_alpha), rounding, ImDrawCornerFlags_TopLeft|ImDrawCornerFlags_BotLeft);
11751  }
11752  else
11753  {
11754  // Because GetColorU32() multiplies by the global style Alpha and we don't want to display a checkerboard if the source code had no alpha
11755  ImVec4 col_source = (flags & ImGuiColorEditFlags_AlphaPreview) ? col : col_without_alpha;
11756  if (col_source.w < 1.0f)
11757  RenderColorRectWithAlphaCheckerboard(bb_inner.Min, bb_inner.Max, GetColorU32(col_source), grid_step, ImVec2(off, off), rounding);
11758  else
11759  window->DrawList->AddRectFilled(bb_inner.Min, bb_inner.Max, GetColorU32(col_source), rounding, ImDrawCornerFlags_All);
11760  }
11761  RenderNavHighlight(bb, id);
11762  if (g.Style.FrameBorderSize > 0.0f)
11763  RenderFrameBorder(bb.Min, bb.Max, rounding);
11764  else
11765  window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding); // Color button are often in need of some sort of border
11766 
11767  // Drag and Drop Source
11768  if (g.ActiveId == id && BeginDragDropSource()) // NB: The ActiveId test is merely an optional micro-optimization
11769  {
11770  if (flags & ImGuiColorEditFlags_NoAlpha)
11772  else
11774  ColorButton(desc_id, col, flags);
11775  SameLine();
11776  TextUnformatted("Color");
11778  hovered = false;
11779  }
11780 
11781  // Tooltip
11782  if (!(flags & ImGuiColorEditFlags_NoTooltip) && hovered)
11783  ColorTooltip(desc_id, &col.x, flags & (ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf));
11784 
11785  return pressed;
11786 }
11787 
11788 bool ImGui::ColorEdit3(const char* label, float col[3], ImGuiColorEditFlags flags)
11789 {
11790  return ColorEdit4(label, col, flags | ImGuiColorEditFlags_NoAlpha);
11791 }
11792 
11794 {
11795  bool allow_opt_inputs = !(flags & ImGuiColorEditFlags__InputsMask);
11796  bool allow_opt_datatype = !(flags & ImGuiColorEditFlags__DataTypeMask);
11797  if ((!allow_opt_inputs && !allow_opt_datatype) || !BeginPopup("context"))
11798  return;
11799  ImGuiContext& g = *GImGui;
11801  if (allow_opt_inputs)
11802  {
11806  }
11807  if (allow_opt_datatype)
11808  {
11809  if (allow_opt_inputs) Separator();
11810  if (RadioButton("0..255", (opts & ImGuiColorEditFlags_Uint8) != 0)) opts = (opts & ~ImGuiColorEditFlags__DataTypeMask) | ImGuiColorEditFlags_Uint8;
11811  if (RadioButton("0.00..1.00", (opts & ImGuiColorEditFlags_Float) != 0)) opts = (opts & ~ImGuiColorEditFlags__DataTypeMask) | ImGuiColorEditFlags_Float;
11812  }
11813 
11814  if (allow_opt_inputs || allow_opt_datatype)
11815  Separator();
11816  if (Button("Copy as..", ImVec2(-1,0)))
11817  OpenPopup("Copy");
11818  if (BeginPopup("Copy"))
11819  {
11820  int cr = IM_F32_TO_INT8_SAT(col[0]), cg = IM_F32_TO_INT8_SAT(col[1]), cb = IM_F32_TO_INT8_SAT(col[2]), ca = (flags & ImGuiColorEditFlags_NoAlpha) ? 255 : IM_F32_TO_INT8_SAT(col[3]);
11821  char buf[64];
11822  ImFormatString(buf, IM_ARRAYSIZE(buf), "(%.3ff, %.3ff, %.3ff, %.3ff)", col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]);
11823  if (Selectable(buf))
11824  SetClipboardText(buf);
11825  ImFormatString(buf, IM_ARRAYSIZE(buf), "(%d,%d,%d,%d)", cr, cg, cb, ca);
11826  if (Selectable(buf))
11827  SetClipboardText(buf);
11828  if (flags & ImGuiColorEditFlags_NoAlpha)
11829  ImFormatString(buf, IM_ARRAYSIZE(buf), "0x%02X%02X%02X", cr, cg, cb);
11830  else
11831  ImFormatString(buf, IM_ARRAYSIZE(buf), "0x%02X%02X%02X%02X", cr, cg, cb, ca);
11832  if (Selectable(buf))
11833  SetClipboardText(buf);
11834  EndPopup();
11835  }
11836 
11837  g.ColorEditOptions = opts;
11838  EndPopup();
11839 }
11840 
11841 static void ColorPickerOptionsPopup(ImGuiColorEditFlags flags, const float* ref_col)
11842 {
11843  bool allow_opt_picker = !(flags & ImGuiColorEditFlags__PickerMask);
11844  bool allow_opt_alpha_bar = !(flags & ImGuiColorEditFlags_NoAlpha) && !(flags & ImGuiColorEditFlags_AlphaBar);
11845  if ((!allow_opt_picker && !allow_opt_alpha_bar) || !ImGui::BeginPopup("context"))
11846  return;
11847  ImGuiContext& g = *GImGui;
11848  if (allow_opt_picker)
11849  {
11850  ImVec2 picker_size(g.FontSize * 8, ImMax(g.FontSize * 8 - (ImGui::GetFrameHeight() + g.Style.ItemInnerSpacing.x), 1.0f)); // FIXME: Picker size copied from main picker function
11851  ImGui::PushItemWidth(picker_size.x);
11852  for (int picker_type = 0; picker_type < 2; picker_type++)
11853  {
11854  // Draw small/thumbnail version of each picker type (over an invisible button for selection)
11855  if (picker_type > 0) ImGui::Separator();
11856  ImGui::PushID(picker_type);
11858  if (picker_type == 0) picker_flags |= ImGuiColorEditFlags_PickerHueBar;
11859  if (picker_type == 1) picker_flags |= ImGuiColorEditFlags_PickerHueWheel;
11860  ImVec2 backup_pos = ImGui::GetCursorScreenPos();
11861  if (ImGui::Selectable("##selectable", false, 0, picker_size)) // By default, Selectable() is closing popup
11863  ImGui::SetCursorScreenPos(backup_pos);
11864  ImVec4 dummy_ref_col;
11865  memcpy(&dummy_ref_col.x, ref_col, sizeof(float) * (picker_flags & ImGuiColorEditFlags_NoAlpha ? 3 : 4));
11866  ImGui::ColorPicker4("##dummypicker", &dummy_ref_col.x, picker_flags);
11867  ImGui::PopID();
11868  }
11870  }
11871  if (allow_opt_alpha_bar)
11872  {
11873  if (allow_opt_picker) ImGui::Separator();
11874  ImGui::CheckboxFlags("Alpha Bar", (unsigned int*)&g.ColorEditOptions, ImGuiColorEditFlags_AlphaBar);
11875  }
11876  ImGui::EndPopup();
11877 }
11878 
11879 // Edit colors components (each component in 0.0f..1.0f range).
11880 // See enum ImGuiColorEditFlags_ for available options. e.g. Only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is set.
11881 // With typical options: Left-click on colored square to open color picker. Right-click to open option menu. CTRL-Click over input fields to edit them and TAB to go to next item.
11882 bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags)
11883 {
11884  ImGuiWindow* window = GetCurrentWindow();
11885  if (window->SkipItems)
11886  return false;
11887 
11888  ImGuiContext& g = *GImGui;
11889  const ImGuiStyle& style = g.Style;
11890  const float square_sz = GetFrameHeight();
11891  const float w_extra = (flags & ImGuiColorEditFlags_NoSmallPreview) ? 0.0f : (square_sz + style.ItemInnerSpacing.x);
11892  const float w_items_all = CalcItemWidth() - w_extra;
11893  const char* label_display_end = FindRenderedTextEnd(label);
11894 
11895  BeginGroup();
11896  PushID(label);
11897 
11898  // If we're not showing any slider there's no point in doing any HSV conversions
11899  const ImGuiColorEditFlags flags_untouched = flags;
11900  if (flags & ImGuiColorEditFlags_NoInputs)
11902 
11903  // Context menu: display and modify options (before defaults are applied)
11904  if (!(flags & ImGuiColorEditFlags_NoOptions))
11905  ColorEditOptionsPopup(col, flags);
11906 
11907  // Read stored options
11908  if (!(flags & ImGuiColorEditFlags__InputsMask))
11909  flags |= (g.ColorEditOptions & ImGuiColorEditFlags__InputsMask);
11910  if (!(flags & ImGuiColorEditFlags__DataTypeMask))
11911  flags |= (g.ColorEditOptions & ImGuiColorEditFlags__DataTypeMask);
11912  if (!(flags & ImGuiColorEditFlags__PickerMask))
11913  flags |= (g.ColorEditOptions & ImGuiColorEditFlags__PickerMask);
11914  flags |= (g.ColorEditOptions & ~(ImGuiColorEditFlags__InputsMask | ImGuiColorEditFlags__DataTypeMask | ImGuiColorEditFlags__PickerMask));
11915 
11916  const bool alpha = (flags & ImGuiColorEditFlags_NoAlpha) == 0;
11917  const bool hdr = (flags & ImGuiColorEditFlags_HDR) != 0;
11918  const int components = alpha ? 4 : 3;
11919 
11920  // Convert to the formats we need
11921  float f[4] = { col[0], col[1], col[2], alpha ? col[3] : 1.0f };
11922  if (flags & ImGuiColorEditFlags_HSV)
11923  ColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]);
11925 
11926  bool value_changed = false;
11927  bool value_changed_as_float = false;
11928 
11929  if ((flags & (ImGuiColorEditFlags_RGB | ImGuiColorEditFlags_HSV)) != 0 && (flags & ImGuiColorEditFlags_NoInputs) == 0)
11930  {
11931  // RGB/HSV 0..255 Sliders
11932  const float w_item_one = ImMax(1.0f, (float)(int)((w_items_all - (style.ItemInnerSpacing.x) * (components-1)) / (float)components));
11933  const float w_item_last = ImMax(1.0f, (float)(int)(w_items_all - (w_item_one + style.ItemInnerSpacing.x) * (components-1)));
11934 
11935  const bool hide_prefix = (w_item_one <= CalcTextSize((flags & ImGuiColorEditFlags_Float) ? "M:0.000" : "M:000").x);
11936  const char* ids[4] = { "##X", "##Y", "##Z", "##W" };
11937  const char* fmt_table_int[3][4] =
11938  {
11939  { "%3d", "%3d", "%3d", "%3d" }, // Short display
11940  { "R:%3d", "G:%3d", "B:%3d", "A:%3d" }, // Long display for RGBA
11941  { "H:%3d", "S:%3d", "V:%3d", "A:%3d" } // Long display for HSVA
11942  };
11943  const char* fmt_table_float[3][4] =
11944  {
11945  { "%0.3f", "%0.3f", "%0.3f", "%0.3f" }, // Short display
11946  { "R:%0.3f", "G:%0.3f", "B:%0.3f", "A:%0.3f" }, // Long display for RGBA
11947  { "H:%0.3f", "S:%0.3f", "V:%0.3f", "A:%0.3f" } // Long display for HSVA
11948  };
11949  const int fmt_idx = hide_prefix ? 0 : (flags & ImGuiColorEditFlags_HSV) ? 2 : 1;
11950 
11951  PushItemWidth(w_item_one);
11952  for (int n = 0; n < components; n++)
11953  {
11954  if (n > 0)
11955  SameLine(0, style.ItemInnerSpacing.x);
11956  if (n + 1 == components)
11957  PushItemWidth(w_item_last);
11958  if (flags & ImGuiColorEditFlags_Float)
11959  value_changed = value_changed_as_float = value_changed | DragFloat(ids[n], &f[n], 1.0f/255.0f, 0.0f, hdr ? 0.0f : 1.0f, fmt_table_float[fmt_idx][n]);
11960  else
11961  value_changed |= DragInt(ids[n], &i[n], 1.0f, 0, hdr ? 0 : 255, fmt_table_int[fmt_idx][n]);
11962  if (!(flags & ImGuiColorEditFlags_NoOptions))
11963  OpenPopupOnItemClick("context");
11964  }
11965  PopItemWidth();
11966  PopItemWidth();
11967  }
11968  else if ((flags & ImGuiColorEditFlags_HEX) != 0 && (flags & ImGuiColorEditFlags_NoInputs) == 0)
11969  {
11970  // RGB Hexadecimal Input
11971  char buf[64];
11972  if (alpha)
11973  ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X%02X", ImClamp(i[0],0,255), ImClamp(i[1],0,255), ImClamp(i[2],0,255), ImClamp(i[3],0,255));
11974  else
11975  ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X", ImClamp(i[0],0,255), ImClamp(i[1],0,255), ImClamp(i[2],0,255));
11976  PushItemWidth(w_items_all);
11977  if (InputText("##Text", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase))
11978  {
11979  value_changed = true;
11980  char* p = buf;
11981  while (*p == '#' || ImCharIsBlankA(*p))
11982  p++;
11983  i[0] = i[1] = i[2] = i[3] = 0;
11984  if (alpha)
11985  sscanf(p, "%02X%02X%02X%02X", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2], (unsigned int*)&i[3]); // Treat at unsigned (%X is unsigned)
11986  else
11987  sscanf(p, "%02X%02X%02X", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2]);
11988  }
11989  if (!(flags & ImGuiColorEditFlags_NoOptions))
11990  OpenPopupOnItemClick("context");
11991  PopItemWidth();
11992  }
11993 
11994  ImGuiWindow* picker_active_window = NULL;
11995  if (!(flags & ImGuiColorEditFlags_NoSmallPreview))
11996  {
11997  if (!(flags & ImGuiColorEditFlags_NoInputs))
11998  SameLine(0, style.ItemInnerSpacing.x);
11999 
12000  const ImVec4 col_v4(col[0], col[1], col[2], alpha ? col[3] : 1.0f);
12001  if (ColorButton("##ColorButton", col_v4, flags))
12002  {
12003  if (!(flags & ImGuiColorEditFlags_NoPicker))
12004  {
12005  // Store current color and open a picker
12006  g.ColorPickerRef = col_v4;
12007  OpenPopup("picker");
12008  SetNextWindowPos(window->DC.LastItemRect.GetBL() + ImVec2(-1,style.ItemSpacing.y));
12009  }
12010  }
12011  if (!(flags & ImGuiColorEditFlags_NoOptions))
12012  OpenPopupOnItemClick("context");
12013 
12014  if (BeginPopup("picker"))
12015  {
12016  picker_active_window = g.CurrentWindow;
12017  if (label != label_display_end)
12018  {
12019  TextUnformatted(label, label_display_end);
12020  Separator();
12021  }
12022  ImGuiColorEditFlags picker_flags_to_forward = ImGuiColorEditFlags__DataTypeMask | ImGuiColorEditFlags__PickerMask | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaBar;
12023  ImGuiColorEditFlags picker_flags = (flags_untouched & picker_flags_to_forward) | ImGuiColorEditFlags__InputsMask | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaPreviewHalf;
12024  PushItemWidth(square_sz * 12.0f); // Use 256 + bar sizes?
12025  value_changed |= ColorPicker4("##picker", col, picker_flags, &g.ColorPickerRef.x);
12026  PopItemWidth();
12027  EndPopup();
12028  }
12029  }
12030 
12031  if (label != label_display_end && !(flags & ImGuiColorEditFlags_NoLabel))
12032  {
12033  SameLine(0, style.ItemInnerSpacing.x);
12034  TextUnformatted(label, label_display_end);
12035  }
12036 
12037  // Convert back
12038  if (picker_active_window == NULL)
12039  {
12040  if (!value_changed_as_float)
12041  for (int n = 0; n < 4; n++)
12042  f[n] = i[n] / 255.0f;
12043  if (flags & ImGuiColorEditFlags_HSV)
12044  ColorConvertHSVtoRGB(f[0], f[1], f[2], f[0], f[1], f[2]);
12045  if (value_changed)
12046  {
12047  col[0] = f[0];
12048  col[1] = f[1];
12049  col[2] = f[2];
12050  if (alpha)
12051  col[3] = f[3];
12052  }
12053  }
12054 
12055  PopID();
12056  EndGroup();
12057 
12058  // Drag and Drop Target
12059  if ((window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect) && BeginDragDropTarget()) // NB: The flag test is merely an optional micro-optimization, BeginDragDropTarget() does the same test.
12060  {
12062  {
12063  memcpy((float*)col, payload->Data, sizeof(float) * 3);
12064  value_changed = true;
12065  }
12067  {
12068  memcpy((float*)col, payload->Data, sizeof(float) * components);
12069  value_changed = true;
12070  }
12072  }
12073 
12074  // When picker is being actively used, use its active id so IsItemActive() will function on ColorEdit4().
12075  if (picker_active_window && g.ActiveId != 0 && g.ActiveIdWindow == picker_active_window)
12076  window->DC.LastItemId = g.ActiveId;
12077 
12078  return value_changed;
12079 }
12080 
12081 bool ImGui::ColorPicker3(const char* label, float col[3], ImGuiColorEditFlags flags)
12082 {
12083  float col4[4] = { col[0], col[1], col[2], 1.0f };
12084  if (!ColorPicker4(label, col4, flags | ImGuiColorEditFlags_NoAlpha))
12085  return false;
12086  col[0] = col4[0]; col[1] = col4[1]; col[2] = col4[2];
12087  return true;
12088 }
12089 
12090 // 'pos' is position of the arrow tip. half_sz.x is length from base to tip. half_sz.y is length on each side.
12091 static void RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col)
12092 {
12093  switch (direction)
12094  {
12095  case ImGuiDir_Left: draw_list->AddTriangleFilled(ImVec2(pos.x + half_sz.x, pos.y - half_sz.y), ImVec2(pos.x + half_sz.x, pos.y + half_sz.y), pos, col); return;
12096  case ImGuiDir_Right: draw_list->AddTriangleFilled(ImVec2(pos.x - half_sz.x, pos.y + half_sz.y), ImVec2(pos.x - half_sz.x, pos.y - half_sz.y), pos, col); return;
12097  case ImGuiDir_Up: draw_list->AddTriangleFilled(ImVec2(pos.x + half_sz.x, pos.y + half_sz.y), ImVec2(pos.x - half_sz.x, pos.y + half_sz.y), pos, col); return;
12098  case ImGuiDir_Down: draw_list->AddTriangleFilled(ImVec2(pos.x - half_sz.x, pos.y - half_sz.y), ImVec2(pos.x + half_sz.x, pos.y - half_sz.y), pos, col); return;
12099  case ImGuiDir_None: case ImGuiDir_COUNT: break; // Fix warnings
12100  }
12101 }
12102 
12103 static void RenderArrowsForVerticalBar(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, float bar_w)
12104 {
12105  RenderArrow(draw_list, ImVec2(pos.x + half_sz.x + 1, pos.y), ImVec2(half_sz.x + 2, half_sz.y + 1), ImGuiDir_Right, IM_COL32_BLACK);
12106  RenderArrow(draw_list, ImVec2(pos.x + half_sz.x, pos.y), half_sz, ImGuiDir_Right, IM_COL32_WHITE);
12107  RenderArrow(draw_list, ImVec2(pos.x + bar_w - half_sz.x - 1, pos.y), ImVec2(half_sz.x + 2, half_sz.y + 1), ImGuiDir_Left, IM_COL32_BLACK);
12108  RenderArrow(draw_list, ImVec2(pos.x + bar_w - half_sz.x, pos.y), half_sz, ImGuiDir_Left, IM_COL32_WHITE);
12109 }
12110 
12111 // ColorPicker
12112 // Note: only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is set.
12113 // FIXME: we adjust the big color square height based on item width, which may cause a flickering feedback loop (if automatic height makes a vertical scrollbar appears, affecting automatic width..)
12114 bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags flags, const float* ref_col)
12115 {
12116  ImGuiContext& g = *GImGui;
12117  ImGuiWindow* window = GetCurrentWindow();
12118  ImDrawList* draw_list = window->DrawList;
12119 
12120  ImGuiStyle& style = g.Style;
12121  ImGuiIO& io = g.IO;
12122 
12123  PushID(label);
12124  BeginGroup();
12125 
12126  if (!(flags & ImGuiColorEditFlags_NoSidePreview))
12128 
12129  // Context menu: display and store options.
12130  if (!(flags & ImGuiColorEditFlags_NoOptions))
12131  ColorPickerOptionsPopup(flags, col);
12132 
12133  // Read stored options
12134  if (!(flags & ImGuiColorEditFlags__PickerMask))
12136  IM_ASSERT(ImIsPowerOfTwo((int)(flags & ImGuiColorEditFlags__PickerMask))); // Check that only 1 is selected
12137  if (!(flags & ImGuiColorEditFlags_NoOptions))
12139 
12140  // Setup
12141  int components = (flags & ImGuiColorEditFlags_NoAlpha) ? 3 : 4;
12142  bool alpha_bar = (flags & ImGuiColorEditFlags_AlphaBar) && !(flags & ImGuiColorEditFlags_NoAlpha);
12143  ImVec2 picker_pos = window->DC.CursorPos;
12144  float square_sz = GetFrameHeight();
12145  float bars_width = square_sz; // Arbitrary smallish width of Hue/Alpha picking bars
12146  float sv_picker_size = ImMax(bars_width * 1, CalcItemWidth() - (alpha_bar ? 2 : 1) * (bars_width + style.ItemInnerSpacing.x)); // Saturation/Value picking box
12147  float bar0_pos_x = picker_pos.x + sv_picker_size + style.ItemInnerSpacing.x;
12148  float bar1_pos_x = bar0_pos_x + bars_width + style.ItemInnerSpacing.x;
12149  float bars_triangles_half_sz = (float)(int)(bars_width * 0.20f);
12150 
12151  float backup_initial_col[4];
12152  memcpy(backup_initial_col, col, components * sizeof(float));
12153 
12154  float wheel_thickness = sv_picker_size * 0.08f;
12155  float wheel_r_outer = sv_picker_size * 0.50f;
12156  float wheel_r_inner = wheel_r_outer - wheel_thickness;
12157  ImVec2 wheel_center(picker_pos.x + (sv_picker_size + bars_width)*0.5f, picker_pos.y + sv_picker_size*0.5f);
12158 
12159  // Note: the triangle is displayed rotated with triangle_pa pointing to Hue, but most coordinates stays unrotated for logic.
12160  float triangle_r = wheel_r_inner - (int)(sv_picker_size * 0.027f);
12161  ImVec2 triangle_pa = ImVec2(triangle_r, 0.0f); // Hue point.
12162  ImVec2 triangle_pb = ImVec2(triangle_r * -0.5f, triangle_r * -0.866025f); // Black point.
12163  ImVec2 triangle_pc = ImVec2(triangle_r * -0.5f, triangle_r * +0.866025f); // White point.
12164 
12165  float H,S,V;
12166  ColorConvertRGBtoHSV(col[0], col[1], col[2], H, S, V);
12167 
12168  bool value_changed = false, value_changed_h = false, value_changed_sv = false;
12169 
12170  PushItemFlag(ImGuiItemFlags_NoNav, true);
12172  {
12173  // Hue wheel + SV triangle logic
12174  InvisibleButton("hsv", ImVec2(sv_picker_size + style.ItemInnerSpacing.x + bars_width, sv_picker_size));
12175  if (IsItemActive())
12176  {
12177  ImVec2 initial_off = g.IO.MouseClickedPos[0] - wheel_center;
12178  ImVec2 current_off = g.IO.MousePos - wheel_center;
12179  float initial_dist2 = ImLengthSqr(initial_off);
12180  if (initial_dist2 >= (wheel_r_inner-1)*(wheel_r_inner-1) && initial_dist2 <= (wheel_r_outer+1)*(wheel_r_outer+1))
12181  {
12182  // Interactive with Hue wheel
12183  H = ImAtan2(current_off.y, current_off.x) / IM_PI*0.5f;
12184  if (H < 0.0f)
12185  H += 1.0f;
12186  value_changed = value_changed_h = true;
12187  }
12188  float cos_hue_angle = ImCos(-H * 2.0f * IM_PI);
12189  float sin_hue_angle = ImSin(-H * 2.0f * IM_PI);
12190  if (ImTriangleContainsPoint(triangle_pa, triangle_pb, triangle_pc, ImRotate(initial_off, cos_hue_angle, sin_hue_angle)))
12191  {
12192  // Interacting with SV triangle
12193  ImVec2 current_off_unrotated = ImRotate(current_off, cos_hue_angle, sin_hue_angle);
12194  if (!ImTriangleContainsPoint(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated))
12195  current_off_unrotated = ImTriangleClosestPoint(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated);
12196  float uu, vv, ww;
12197  ImTriangleBarycentricCoords(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated, uu, vv, ww);
12198  V = ImClamp(1.0f - vv, 0.0001f, 1.0f);
12199  S = ImClamp(uu / V, 0.0001f, 1.0f);
12200  value_changed = value_changed_sv = true;
12201  }
12202  }
12203  if (!(flags & ImGuiColorEditFlags_NoOptions))
12204  OpenPopupOnItemClick("context");
12205  }
12206  else if (flags & ImGuiColorEditFlags_PickerHueBar)
12207  {
12208  // SV rectangle logic
12209  InvisibleButton("sv", ImVec2(sv_picker_size, sv_picker_size));
12210  if (IsItemActive())
12211  {
12212  S = ImSaturate((io.MousePos.x - picker_pos.x) / (sv_picker_size-1));
12213  V = 1.0f - ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size-1));
12214  value_changed = value_changed_sv = true;
12215  }
12216  if (!(flags & ImGuiColorEditFlags_NoOptions))
12217  OpenPopupOnItemClick("context");
12218 
12219  // Hue bar logic
12220  SetCursorScreenPos(ImVec2(bar0_pos_x, picker_pos.y));
12221  InvisibleButton("hue", ImVec2(bars_width, sv_picker_size));
12222  if (IsItemActive())
12223  {
12224  H = ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size-1));
12225  value_changed = value_changed_h = true;
12226  }
12227  }
12228 
12229  // Alpha bar logic
12230  if (alpha_bar)
12231  {
12232  SetCursorScreenPos(ImVec2(bar1_pos_x, picker_pos.y));
12233  InvisibleButton("alpha", ImVec2(bars_width, sv_picker_size));
12234  if (IsItemActive())
12235  {
12236  col[3] = 1.0f - ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size-1));
12237  value_changed = true;
12238  }
12239  }
12240  PopItemFlag(); // ImGuiItemFlags_NoNav
12241 
12242  if (!(flags & ImGuiColorEditFlags_NoSidePreview))
12243  {
12244  SameLine(0, style.ItemInnerSpacing.x);
12245  BeginGroup();
12246  }
12247 
12248  if (!(flags & ImGuiColorEditFlags_NoLabel))
12249  {
12250  const char* label_display_end = FindRenderedTextEnd(label);
12251  if (label != label_display_end)
12252  {
12253  if ((flags & ImGuiColorEditFlags_NoSidePreview))
12254  SameLine(0, style.ItemInnerSpacing.x);
12255  TextUnformatted(label, label_display_end);
12256  }
12257  }
12258 
12259  if (!(flags & ImGuiColorEditFlags_NoSidePreview))
12260  {
12261  PushItemFlag(ImGuiItemFlags_NoNavDefaultFocus, true);
12262  ImVec4 col_v4(col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]);
12263  if ((flags & ImGuiColorEditFlags_NoLabel))
12264  Text("Current");
12266  if (ref_col != NULL)
12267  {
12268  Text("Original");
12269  ImVec4 ref_col_v4(ref_col[0], ref_col[1], ref_col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : ref_col[3]);
12271  {
12272  memcpy(col, ref_col, components * sizeof(float));
12273  value_changed = true;
12274  }
12275  }
12276  PopItemFlag();
12277  EndGroup();
12278  }
12279 
12280  // Convert back color to RGB
12281  if (value_changed_h || value_changed_sv)
12282  ColorConvertHSVtoRGB(H >= 1.0f ? H - 10 * 1e-6f : H, S > 0.0f ? S : 10*1e-6f, V > 0.0f ? V : 1e-6f, col[0], col[1], col[2]);
12283 
12284  // R,G,B and H,S,V slider color editor
12285  if ((flags & ImGuiColorEditFlags_NoInputs) == 0)
12286  {
12287  PushItemWidth((alpha_bar ? bar1_pos_x : bar0_pos_x) + bars_width - picker_pos.x);
12289  ImGuiColorEditFlags sub_flags = (flags & sub_flags_to_forward) | ImGuiColorEditFlags_NoPicker;
12290  if (flags & ImGuiColorEditFlags_RGB || (flags & ImGuiColorEditFlags__InputsMask) == 0)
12291  value_changed |= ColorEdit4("##rgb", col, sub_flags | ImGuiColorEditFlags_RGB);
12292  if (flags & ImGuiColorEditFlags_HSV || (flags & ImGuiColorEditFlags__InputsMask) == 0)
12293  value_changed |= ColorEdit4("##hsv", col, sub_flags | ImGuiColorEditFlags_HSV);
12294  if (flags & ImGuiColorEditFlags_HEX || (flags & ImGuiColorEditFlags__InputsMask) == 0)
12295  value_changed |= ColorEdit4("##hex", col, sub_flags | ImGuiColorEditFlags_HEX);
12296  PopItemWidth();
12297  }
12298 
12299  // Try to cancel hue wrap (after ColorEdit), if any
12300  if (value_changed)
12301  {
12302  float new_H, new_S, new_V;
12303  ColorConvertRGBtoHSV(col[0], col[1], col[2], new_H, new_S, new_V);
12304  if (new_H <= 0 && H > 0)
12305  {
12306  if (new_V <= 0 && V != new_V)
12307  ColorConvertHSVtoRGB(H, S, new_V <= 0 ? V * 0.5f : new_V, col[0], col[1], col[2]);
12308  else if (new_S <= 0)
12309  ColorConvertHSVtoRGB(H, new_S <= 0 ? S * 0.5f : new_S, new_V, col[0], col[1], col[2]);
12310  }
12311  }
12312 
12313  ImVec4 hue_color_f(1, 1, 1, 1); ColorConvertHSVtoRGB(H, 1, 1, hue_color_f.x, hue_color_f.y, hue_color_f.z);
12314  ImU32 hue_color32 = ColorConvertFloat4ToU32(hue_color_f);
12315  ImU32 col32_no_alpha = ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 1.0f));
12316 
12317  const ImU32 hue_colors[6+1] = { IM_COL32(255,0,0,255), IM_COL32(255,255,0,255), IM_COL32(0,255,0,255), IM_COL32(0,255,255,255), IM_COL32(0,0,255,255), IM_COL32(255,0,255,255), IM_COL32(255,0,0,255) };
12318  ImVec2 sv_cursor_pos;
12319 
12320  if (flags & ImGuiColorEditFlags_PickerHueWheel)
12321  {
12322  // Render Hue Wheel
12323  const float aeps = 1.5f / wheel_r_outer; // Half a pixel arc length in radians (2pi cancels out).
12324  const int segment_per_arc = ImMax(4, (int)wheel_r_outer / 12);
12325  for (int n = 0; n < 6; n++)
12326  {
12327  const float a0 = (n) /6.0f * 2.0f * IM_PI - aeps;
12328  const float a1 = (n+1.0f)/6.0f * 2.0f * IM_PI + aeps;
12329  const int vert_start_idx = draw_list->VtxBuffer.Size;
12330  draw_list->PathArcTo(wheel_center, (wheel_r_inner + wheel_r_outer)*0.5f, a0, a1, segment_per_arc);
12331  draw_list->PathStroke(IM_COL32_WHITE, false, wheel_thickness);
12332  const int vert_end_idx = draw_list->VtxBuffer.Size;
12333 
12334  // Paint colors over existing vertices
12335  ImVec2 gradient_p0(wheel_center.x + ImCos(a0) * wheel_r_inner, wheel_center.y + ImSin(a0) * wheel_r_inner);
12336  ImVec2 gradient_p1(wheel_center.x + ImCos(a1) * wheel_r_inner, wheel_center.y + ImSin(a1) * wheel_r_inner);
12337  ShadeVertsLinearColorGradientKeepAlpha(draw_list->VtxBuffer.Data + vert_start_idx, draw_list->VtxBuffer.Data + vert_end_idx, gradient_p0, gradient_p1, hue_colors[n], hue_colors[n+1]);
12338  }
12339 
12340  // Render Cursor + preview on Hue Wheel
12341  float cos_hue_angle = ImCos(H * 2.0f * IM_PI);
12342  float sin_hue_angle = ImSin(H * 2.0f * IM_PI);
12343  ImVec2 hue_cursor_pos(wheel_center.x + cos_hue_angle * (wheel_r_inner+wheel_r_outer)*0.5f, wheel_center.y + sin_hue_angle * (wheel_r_inner+wheel_r_outer)*0.5f);
12344  float hue_cursor_rad = value_changed_h ? wheel_thickness * 0.65f : wheel_thickness * 0.55f;
12345  int hue_cursor_segments = ImClamp((int)(hue_cursor_rad / 1.4f), 9, 32);
12346  draw_list->AddCircleFilled(hue_cursor_pos, hue_cursor_rad, hue_color32, hue_cursor_segments);
12347  draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad+1, IM_COL32(128,128,128,255), hue_cursor_segments);
12348  draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad, IM_COL32_WHITE, hue_cursor_segments);
12349 
12350  // Render SV triangle (rotated according to hue)
12351  ImVec2 tra = wheel_center + ImRotate(triangle_pa, cos_hue_angle, sin_hue_angle);
12352  ImVec2 trb = wheel_center + ImRotate(triangle_pb, cos_hue_angle, sin_hue_angle);
12353  ImVec2 trc = wheel_center + ImRotate(triangle_pc, cos_hue_angle, sin_hue_angle);
12354  ImVec2 uv_white = GetFontTexUvWhitePixel();
12355  draw_list->PrimReserve(6, 6);
12356  draw_list->PrimVtx(tra, uv_white, hue_color32);
12357  draw_list->PrimVtx(trb, uv_white, hue_color32);
12358  draw_list->PrimVtx(trc, uv_white, IM_COL32_WHITE);
12359  draw_list->PrimVtx(tra, uv_white, IM_COL32_BLACK_TRANS);
12360  draw_list->PrimVtx(trb, uv_white, IM_COL32_BLACK);
12361  draw_list->PrimVtx(trc, uv_white, IM_COL32_BLACK_TRANS);
12362  draw_list->AddTriangle(tra, trb, trc, IM_COL32(128,128,128,255), 1.5f);
12363  sv_cursor_pos = ImLerp(ImLerp(trc, tra, ImSaturate(S)), trb, ImSaturate(1 - V));
12364  }
12365  else if (flags & ImGuiColorEditFlags_PickerHueBar)
12366  {
12367  // Render SV Square
12368  draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size,sv_picker_size), IM_COL32_WHITE, hue_color32, hue_color32, IM_COL32_WHITE);
12369  draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size,sv_picker_size), IM_COL32_BLACK_TRANS, IM_COL32_BLACK_TRANS, IM_COL32_BLACK, IM_COL32_BLACK);
12370  RenderFrameBorder(picker_pos, picker_pos + ImVec2(sv_picker_size,sv_picker_size), 0.0f);
12371  sv_cursor_pos.x = ImClamp((float)(int)(picker_pos.x + ImSaturate(S) * sv_picker_size + 0.5f), picker_pos.x + 2, picker_pos.x + sv_picker_size - 2); // Sneakily prevent the circle to stick out too much
12372  sv_cursor_pos.y = ImClamp((float)(int)(picker_pos.y + ImSaturate(1 - V) * sv_picker_size + 0.5f), picker_pos.y + 2, picker_pos.y + sv_picker_size - 2);
12373 
12374  // Render Hue Bar
12375  for (int i = 0; i < 6; ++i)
12376  draw_list->AddRectFilledMultiColor(ImVec2(bar0_pos_x, picker_pos.y + i * (sv_picker_size / 6)), ImVec2(bar0_pos_x + bars_width, picker_pos.y + (i + 1) * (sv_picker_size / 6)), hue_colors[i], hue_colors[i], hue_colors[i + 1], hue_colors[i + 1]);
12377  float bar0_line_y = (float)(int)(picker_pos.y + H * sv_picker_size + 0.5f);
12378  RenderFrameBorder(ImVec2(bar0_pos_x, picker_pos.y), ImVec2(bar0_pos_x + bars_width, picker_pos.y + sv_picker_size), 0.0f);
12379  RenderArrowsForVerticalBar(draw_list, ImVec2(bar0_pos_x - 1, bar0_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f);
12380  }
12381 
12382  // Render cursor/preview circle (clamp S/V within 0..1 range because floating points colors may lead HSV values to be out of range)
12383  float sv_cursor_rad = value_changed_sv ? 10.0f : 6.0f;
12384  draw_list->AddCircleFilled(sv_cursor_pos, sv_cursor_rad, col32_no_alpha, 12);
12385  draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad+1, IM_COL32(128,128,128,255), 12);
12386  draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad, IM_COL32_WHITE, 12);
12387 
12388  // Render alpha bar
12389  if (alpha_bar)
12390  {
12391  float alpha = ImSaturate(col[3]);
12392  ImRect bar1_bb(bar1_pos_x, picker_pos.y, bar1_pos_x + bars_width, picker_pos.y + sv_picker_size);
12393  RenderColorRectWithAlphaCheckerboard(bar1_bb.Min, bar1_bb.Max, IM_COL32(0,0,0,0), bar1_bb.GetWidth() / 2.0f, ImVec2(0.0f, 0.0f));
12394  draw_list->AddRectFilledMultiColor(bar1_bb.Min, bar1_bb.Max, col32_no_alpha, col32_no_alpha, col32_no_alpha & ~IM_COL32_A_MASK, col32_no_alpha & ~IM_COL32_A_MASK);
12395  float bar1_line_y = (float)(int)(picker_pos.y + (1.0f - alpha) * sv_picker_size + 0.5f);
12396  RenderFrameBorder(bar1_bb.Min, bar1_bb.Max, 0.0f);
12397  RenderArrowsForVerticalBar(draw_list, ImVec2(bar1_pos_x - 1, bar1_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f);
12398  }
12399 
12400  EndGroup();
12401  PopID();
12402 
12403  return value_changed && memcmp(backup_initial_col, col, components * sizeof(float));
12404 }
12405 
12406 // Horizontal separating line.
12408 {
12409  ImGuiWindow* window = GetCurrentWindow();
12410  if (window->SkipItems)
12411  return;
12412  ImGuiContext& g = *GImGui;
12413 
12414  ImGuiSeparatorFlags flags = 0;
12417  IM_ASSERT(ImIsPowerOfTwo((int)(flags & (ImGuiSeparatorFlags_Horizontal | ImGuiSeparatorFlags_Vertical)))); // Check that only 1 option is selected
12418  if (flags & ImGuiSeparatorFlags_Vertical)
12419  {
12421  return;
12422  }
12423 
12424  // Horizontal Separator
12425  if (window->DC.ColumnsSet)
12426  PopClipRect();
12427 
12428  float x1 = window->Pos.x;
12429  float x2 = window->Pos.x + window->Size.x;
12430  if (!window->DC.GroupStack.empty())
12431  x1 += window->DC.IndentX;
12432 
12433  const ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y+1.0f));
12434  ItemSize(ImVec2(0.0f, 0.0f)); // NB: we don't provide our width so that it doesn't get feed back into AutoFit, we don't provide height to not alter layout.
12435  if (!ItemAdd(bb, 0))
12436  {
12437  if (window->DC.ColumnsSet)
12439  return;
12440  }
12441 
12442  window->DrawList->AddLine(bb.Min, ImVec2(bb.Max.x,bb.Min.y), GetColorU32(ImGuiCol_Separator));
12443 
12444  if (g.LogEnabled)
12445  LogRenderedText(NULL, IM_NEWLINE "--------------------------------");
12446 
12447  if (window->DC.ColumnsSet)
12448  {
12450  window->DC.ColumnsSet->LineMinY = window->DC.CursorPos.y;
12451  }
12452 }
12453 
12455 {
12456  ImGuiWindow* window = GetCurrentWindow();
12457  if (window->SkipItems)
12458  return;
12459  ImGuiContext& g = *GImGui;
12460 
12461  float y1 = window->DC.CursorPos.y;
12462  float y2 = window->DC.CursorPos.y + window->DC.CurrentLineHeight;
12463  const ImRect bb(ImVec2(window->DC.CursorPos.x, y1), ImVec2(window->DC.CursorPos.x + 1.0f, y2));
12464  ItemSize(ImVec2(bb.GetWidth(), 0.0f));
12465  if (!ItemAdd(bb, 0))
12466  return;
12467 
12468  window->DrawList->AddLine(ImVec2(bb.Min.x, bb.Min.y), ImVec2(bb.Min.x, bb.Max.y), GetColorU32(ImGuiCol_Separator));
12469  if (g.LogEnabled)
12470  LogText(" |");
12471 }
12472 
12473 bool ImGui::SplitterBehavior(ImGuiID id, const ImRect& bb, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend)
12474 {
12475  ImGuiContext& g = *GImGui;
12476  ImGuiWindow* window = g.CurrentWindow;
12477 
12478  const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags;
12479  window->DC.ItemFlags |= ImGuiItemFlags_NoNav | ImGuiItemFlags_NoNavDefaultFocus;
12480  bool item_add = ItemAdd(bb, id);
12481  window->DC.ItemFlags = item_flags_backup;
12482  if (!item_add)
12483  return false;
12484 
12485  bool hovered, held;
12486  ImRect bb_interact = bb;
12487  bb_interact.Expand(axis == ImGuiAxis_Y ? ImVec2(0.0f, hover_extend) : ImVec2(hover_extend, 0.0f));
12489  if (g.ActiveId != id)
12491 
12492  if (held || (g.HoveredId == id && g.HoveredIdPreviousFrame == id))
12494 
12495  ImRect bb_render = bb;
12496  if (held)
12497  {
12498  ImVec2 mouse_delta_2d = g.IO.MousePos - g.ActiveIdClickOffset - bb_interact.Min;
12499  float mouse_delta = (axis == ImGuiAxis_Y) ? mouse_delta_2d.y : mouse_delta_2d.x;
12500 
12501  // Minimum pane size
12502  if (mouse_delta < min_size1 - *size1)
12503  mouse_delta = min_size1 - *size1;
12504  if (mouse_delta > *size2 - min_size2)
12505  mouse_delta = *size2 - min_size2;
12506 
12507  // Apply resize
12508  *size1 += mouse_delta;
12509  *size2 -= mouse_delta;
12510  bb_render.Translate((axis == ImGuiAxis_X) ? ImVec2(mouse_delta, 0.0f) : ImVec2(0.0f, mouse_delta));
12511  }
12512 
12513  // Render
12515  window->DrawList->AddRectFilled(bb_render.Min, bb_render.Max, col, g.Style.FrameRounding);
12516 
12517  return held;
12518 }
12519 
12521 {
12522  ImGuiWindow* window = GetCurrentWindow();
12523  if (window->SkipItems)
12524  return;
12525  ItemSize(ImVec2(0,0));
12526 }
12527 
12528 void ImGui::Dummy(const ImVec2& size)
12529 {
12530  ImGuiWindow* window = GetCurrentWindow();
12531  if (window->SkipItems)
12532  return;
12533 
12534  const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);
12535  ItemSize(bb);
12536  ItemAdd(bb, 0);
12537 }
12538 
12539 bool ImGui::IsRectVisible(const ImVec2& size)
12540 {
12541  ImGuiWindow* window = GetCurrentWindowRead();
12542  return window->ClipRect.Overlaps(ImRect(window->DC.CursorPos, window->DC.CursorPos + size));
12543 }
12544 
12545 bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max)
12546 {
12547  ImGuiWindow* window = GetCurrentWindowRead();
12548  return window->ClipRect.Overlaps(ImRect(rect_min, rect_max));
12549 }
12550 
12551 // Lock horizontal starting position + capture group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.)
12553 {
12554  ImGuiWindow* window = GetCurrentWindow();
12555 
12556  window->DC.GroupStack.resize(window->DC.GroupStack.Size + 1);
12557  ImGuiGroupData& group_data = window->DC.GroupStack.back();
12558  group_data.BackupCursorPos = window->DC.CursorPos;
12559  group_data.BackupCursorMaxPos = window->DC.CursorMaxPos;
12560  group_data.BackupIndentX = window->DC.IndentX;
12561  group_data.BackupGroupOffsetX = window->DC.GroupOffsetX;
12562  group_data.BackupCurrentLineHeight = window->DC.CurrentLineHeight;
12564  group_data.BackupLogLinePosY = window->DC.LogLinePosY;
12565  group_data.BackupActiveIdIsAlive = GImGui->ActiveIdIsAlive;
12566  group_data.AdvanceCursor = true;
12567 
12568  window->DC.GroupOffsetX = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffsetX;
12569  window->DC.IndentX = window->DC.GroupOffsetX;
12570  window->DC.CursorMaxPos = window->DC.CursorPos;
12571  window->DC.CurrentLineHeight = 0.0f;
12572  window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f;
12573 }
12574 
12576 {
12577  ImGuiContext& g = *GImGui;
12578  ImGuiWindow* window = GetCurrentWindow();
12579 
12580  IM_ASSERT(!window->DC.GroupStack.empty()); // Mismatched BeginGroup()/EndGroup() calls
12581 
12582  ImGuiGroupData& group_data = window->DC.GroupStack.back();
12583 
12584  ImRect group_bb(group_data.BackupCursorPos, window->DC.CursorMaxPos);
12585  group_bb.Max = ImMax(group_bb.Min, group_bb.Max);
12586 
12587  window->DC.CursorPos = group_data.BackupCursorPos;
12588  window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos);
12589  window->DC.CurrentLineHeight = group_data.BackupCurrentLineHeight;
12590  window->DC.CurrentLineTextBaseOffset = group_data.BackupCurrentLineTextBaseOffset;
12591  window->DC.IndentX = group_data.BackupIndentX;
12592  window->DC.GroupOffsetX = group_data.BackupGroupOffsetX;
12593  window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f;
12594 
12595  if (group_data.AdvanceCursor)
12596  {
12597  window->DC.CurrentLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrentLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now.
12598  ItemSize(group_bb.GetSize(), group_data.BackupCurrentLineTextBaseOffset);
12599  ItemAdd(group_bb, 0);
12600  }
12601 
12602  // If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive() will be functional on the entire group.
12603  // It would be be neater if we replaced window.DC.LastItemId by e.g. 'bool LastItemIsActive', but if you search for LastItemId you'll notice it is only used in that context.
12604  const bool active_id_within_group = (!group_data.BackupActiveIdIsAlive && g.ActiveIdIsAlive && g.ActiveId && g.ActiveIdWindow->RootWindow == window->RootWindow);
12605  if (active_id_within_group)
12606  window->DC.LastItemId = g.ActiveId;
12607  window->DC.LastItemRect = group_bb;
12608 
12609  window->DC.GroupStack.pop_back();
12610 
12611  //window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255)); // [Debug]
12612 }
12613 
12614 // Gets back to previous line and continue with horizontal layout
12615 // pos_x == 0 : follow right after previous item
12616 // pos_x != 0 : align to specified x position (relative to window/group left)
12617 // spacing_w < 0 : use default spacing if pos_x == 0, no spacing if pos_x != 0
12618 // spacing_w >= 0 : enforce spacing amount
12619 void ImGui::SameLine(float pos_x, float spacing_w)
12620 {
12621  ImGuiWindow* window = GetCurrentWindow();
12622  if (window->SkipItems)
12623  return;
12624 
12625  ImGuiContext& g = *GImGui;
12626  if (pos_x != 0.0f)
12627  {
12628  if (spacing_w < 0.0f) spacing_w = 0.0f;
12629  window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + pos_x + spacing_w + window->DC.GroupOffsetX + window->DC.ColumnsOffsetX;
12630  window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y;
12631  }
12632  else
12633  {
12634  if (spacing_w < 0.0f) spacing_w = g.Style.ItemSpacing.x;
12635  window->DC.CursorPos.x = window->DC.CursorPosPrevLine.x + spacing_w;
12636  window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y;
12637  }
12638  window->DC.CurrentLineHeight = window->DC.PrevLineHeight;
12640 }
12641 
12643 {
12644  ImGuiWindow* window = GetCurrentWindow();
12645  if (window->SkipItems)
12646  return;
12647 
12648  ImGuiContext& g = *GImGui;
12649  const ImGuiLayoutType backup_layout_type = window->DC.LayoutType;
12651  if (window->DC.CurrentLineHeight > 0.0f) // In the event that we are on a line with items that is smaller that FontSize high, we will preserve its height.
12652  ItemSize(ImVec2(0,0));
12653  else
12654  ItemSize(ImVec2(0.0f, g.FontSize));
12655  window->DC.LayoutType = backup_layout_type;
12656 }
12657 
12659 {
12660  ImGuiWindow* window = GetCurrentWindow();
12661  if (window->SkipItems || window->DC.ColumnsSet == NULL)
12662  return;
12663 
12664  ImGuiContext& g = *GImGui;
12665  PopItemWidth();
12666  PopClipRect();
12667 
12668  ImGuiColumnsSet* columns = window->DC.ColumnsSet;
12669  columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y);
12670  if (++columns->Current < columns->Count)
12671  {
12672  // Columns 1+ cancel out IndentX
12673  window->DC.ColumnsOffsetX = GetColumnOffset(columns->Current) - window->DC.IndentX + g.Style.ItemSpacing.x;
12674  window->DrawList->ChannelsSetCurrent(columns->Current);
12675  }
12676  else
12677  {
12678  window->DC.ColumnsOffsetX = 0.0f;
12679  window->DrawList->ChannelsSetCurrent(0);
12680  columns->Current = 0;
12681  columns->LineMinY = columns->LineMaxY;
12682  }
12683  window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX);
12684  window->DC.CursorPos.y = columns->LineMinY;
12685  window->DC.CurrentLineHeight = 0.0f;
12686  window->DC.CurrentLineTextBaseOffset = 0.0f;
12687 
12689  PushItemWidth(GetColumnWidth() * 0.65f); // FIXME: Move on columns setup
12690 }
12691 
12693 {
12694  ImGuiWindow* window = GetCurrentWindowRead();
12695  return window->DC.ColumnsSet ? window->DC.ColumnsSet->Current : 0;
12696 }
12697 
12699 {
12700  ImGuiWindow* window = GetCurrentWindowRead();
12701  return window->DC.ColumnsSet ? window->DC.ColumnsSet->Count : 1;
12702 }
12703 
12704 static float OffsetNormToPixels(const ImGuiColumnsSet* columns, float offset_norm)
12705 {
12706  return offset_norm * (columns->MaxX - columns->MinX);
12707 }
12708 
12709 static float PixelsToOffsetNorm(const ImGuiColumnsSet* columns, float offset)
12710 {
12711  return offset / (columns->MaxX - columns->MinX);
12712 }
12713 
12714 static inline float GetColumnsRectHalfWidth() { return 4.0f; }
12715 
12716 static float GetDraggedColumnOffset(ImGuiColumnsSet* columns, int column_index)
12717 {
12718  // Active (dragged) column always follow mouse. The reason we need this is that dragging a column to the right edge of an auto-resizing
12719  // window creates a feedback loop because we store normalized positions. So while dragging we enforce absolute positioning.
12720  ImGuiContext& g = *GImGui;
12721  ImGuiWindow* window = g.CurrentWindow;
12722  IM_ASSERT(column_index > 0); // We are not supposed to drag column 0.
12723  IM_ASSERT(g.ActiveId == columns->ID + ImGuiID(column_index));
12724 
12725  float x = g.IO.MousePos.x - g.ActiveIdClickOffset.x + GetColumnsRectHalfWidth() - window->Pos.x;
12726  x = ImMax(x, ImGui::GetColumnOffset(column_index - 1) + g.Style.ColumnsMinSpacing);
12727  if ((columns->Flags & ImGuiColumnsFlags_NoPreserveWidths))
12728  x = ImMin(x, ImGui::GetColumnOffset(column_index + 1) - g.Style.ColumnsMinSpacing);
12729 
12730  return x;
12731 }
12732 
12733 float ImGui::GetColumnOffset(int column_index)
12734 {
12735  ImGuiWindow* window = GetCurrentWindowRead();
12736  ImGuiColumnsSet* columns = window->DC.ColumnsSet;
12737  IM_ASSERT(columns != NULL);
12738 
12739  if (column_index < 0)
12740  column_index = columns->Current;
12741  IM_ASSERT(column_index < columns->Columns.Size);
12742 
12743  const float t = columns->Columns[column_index].OffsetNorm;
12744  const float x_offset = ImLerp(columns->MinX, columns->MaxX, t);
12745  return x_offset;
12746 }
12747 
12748 static float GetColumnWidthEx(ImGuiColumnsSet* columns, int column_index, bool before_resize = false)
12749 {
12750  if (column_index < 0)
12751  column_index = columns->Current;
12752 
12753  float offset_norm;
12754  if (before_resize)
12755  offset_norm = columns->Columns[column_index + 1].OffsetNormBeforeResize - columns->Columns[column_index].OffsetNormBeforeResize;
12756  else
12757  offset_norm = columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm;
12758  return OffsetNormToPixels(columns, offset_norm);
12759 }
12760 
12761 float ImGui::GetColumnWidth(int column_index)
12762 {
12763  ImGuiWindow* window = GetCurrentWindowRead();
12764  ImGuiColumnsSet* columns = window->DC.ColumnsSet;
12765  IM_ASSERT(columns != NULL);
12766 
12767  if (column_index < 0)
12768  column_index = columns->Current;
12769  return OffsetNormToPixels(columns, columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm);
12770 }
12771 
12772 void ImGui::SetColumnOffset(int column_index, float offset)
12773 {
12774  ImGuiContext& g = *GImGui;
12775  ImGuiWindow* window = g.CurrentWindow;
12776  ImGuiColumnsSet* columns = window->DC.ColumnsSet;
12777  IM_ASSERT(columns != NULL);
12778 
12779  if (column_index < 0)
12780  column_index = columns->Current;
12781  IM_ASSERT(column_index < columns->Columns.Size);
12782 
12783  const bool preserve_width = !(columns->Flags & ImGuiColumnsFlags_NoPreserveWidths) && (column_index < columns->Count-1);
12784  const float width = preserve_width ? GetColumnWidthEx(columns, column_index, columns->IsBeingResized) : 0.0f;
12785 
12786  if (!(columns->Flags & ImGuiColumnsFlags_NoForceWithinWindow))
12787  offset = ImMin(offset, columns->MaxX - g.Style.ColumnsMinSpacing * (columns->Count - column_index));
12788  columns->Columns[column_index].OffsetNorm = PixelsToOffsetNorm(columns, offset - columns->MinX);
12789 
12790  if (preserve_width)
12791  SetColumnOffset(column_index + 1, offset + ImMax(g.Style.ColumnsMinSpacing, width));
12792 }
12793 
12794 void ImGui::SetColumnWidth(int column_index, float width)
12795 {
12796  ImGuiWindow* window = GetCurrentWindowRead();
12797  ImGuiColumnsSet* columns = window->DC.ColumnsSet;
12798  IM_ASSERT(columns != NULL);
12799 
12800  if (column_index < 0)
12801  column_index = columns->Current;
12802  SetColumnOffset(column_index + 1, GetColumnOffset(column_index) + width);
12803 }
12804 
12805 void ImGui::PushColumnClipRect(int column_index)
12806 {
12807  ImGuiWindow* window = GetCurrentWindowRead();
12808  ImGuiColumnsSet* columns = window->DC.ColumnsSet;
12809  if (column_index < 0)
12810  column_index = columns->Current;
12811 
12812  PushClipRect(columns->Columns[column_index].ClipRect.Min, columns->Columns[column_index].ClipRect.Max, false);
12813 }
12814 
12815 static ImGuiColumnsSet* FindOrAddColumnsSet(ImGuiWindow* window, ImGuiID id)
12816 {
12817  for (int n = 0; n < window->ColumnsStorage.Size; n++)
12818  if (window->ColumnsStorage[n].ID == id)
12819  return &window->ColumnsStorage[n];
12820 
12822  ImGuiColumnsSet* columns = &window->ColumnsStorage.back();
12823  columns->ID = id;
12824  return columns;
12825 }
12826 
12827 void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlags flags)
12828 {
12829  ImGuiContext& g = *GImGui;
12830  ImGuiWindow* window = GetCurrentWindow();
12831 
12832  IM_ASSERT(columns_count > 1);
12833  IM_ASSERT(window->DC.ColumnsSet == NULL); // Nested columns are currently not supported
12834 
12835  // Differentiate column ID with an arbitrary prefix for cases where users name their columns set the same as another widget.
12836  // In addition, when an identifier isn't explicitly provided we include the number of columns in the hash to make it uniquer.
12837  PushID(0x11223347 + (str_id ? 0 : columns_count));
12838  ImGuiID id = window->GetID(str_id ? str_id : "columns");
12839  PopID();
12840 
12841  // Acquire storage for the columns set
12842  ImGuiColumnsSet* columns = FindOrAddColumnsSet(window, id);
12843  IM_ASSERT(columns->ID == id);
12844  columns->Current = 0;
12845  columns->Count = columns_count;
12846  columns->Flags = flags;
12847  window->DC.ColumnsSet = columns;
12848 
12849  // Set state for first column
12850  const float content_region_width = (window->SizeContentsExplicit.x != 0.0f) ? (window->SizeContentsExplicit.x) : (window->InnerClipRect.Max.x - window->Pos.x);
12851  columns->MinX = window->DC.IndentX - g.Style.ItemSpacing.x; // Lock our horizontal range
12852  columns->MaxX = ImMax(content_region_width - window->Scroll.x, columns->MinX + 1.0f);
12853  columns->StartPosY = window->DC.CursorPos.y;
12854  columns->StartMaxPosX = window->DC.CursorMaxPos.x;
12855  columns->LineMinY = columns->LineMaxY = window->DC.CursorPos.y;
12856  window->DC.ColumnsOffsetX = 0.0f;
12857  window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX);
12858 
12859  // Clear data if columns count changed
12860  if (columns->Columns.Size != 0 && columns->Columns.Size != columns_count + 1)
12861  columns->Columns.resize(0);
12862 
12863  // Initialize defaults
12864  columns->IsFirstFrame = (columns->Columns.Size == 0);
12865  if (columns->Columns.Size == 0)
12866  {
12867  columns->Columns.reserve(columns_count + 1);
12868  for (int n = 0; n < columns_count + 1; n++)
12869  {
12870  ImGuiColumnData column;
12871  column.OffsetNorm = n / (float)columns_count;
12872  columns->Columns.push_back(column);
12873  }
12874  }
12875 
12876  for (int n = 0; n < columns_count; n++)
12877  {
12878  // Compute clipping rectangle
12879  ImGuiColumnData* column = &columns->Columns[n];
12880  float clip_x1 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(n) - 1.0f);
12881  float clip_x2 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(n + 1) - 1.0f);
12882  column->ClipRect = ImRect(clip_x1, -FLT_MAX, clip_x2, +FLT_MAX);
12883  column->ClipRect.ClipWith(window->ClipRect);
12884  }
12885 
12886  window->DrawList->ChannelsSplit(columns->Count);
12888  PushItemWidth(GetColumnWidth() * 0.65f);
12889 }
12890 
12892 {
12893  ImGuiContext& g = *GImGui;
12894  ImGuiWindow* window = GetCurrentWindow();
12895  ImGuiColumnsSet* columns = window->DC.ColumnsSet;
12896  IM_ASSERT(columns != NULL);
12897 
12898  PopItemWidth();
12899  PopClipRect();
12900  window->DrawList->ChannelsMerge();
12901 
12902  columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y);
12903  window->DC.CursorPos.y = columns->LineMaxY;
12905  window->DC.CursorMaxPos.x = columns->StartMaxPosX; // Restore cursor max pos, as columns don't grow parent
12906 
12907  // Draw columns borders and handle resize
12908  bool is_being_resized = false;
12909  if (!(columns->Flags & ImGuiColumnsFlags_NoBorder) && !window->SkipItems)
12910  {
12911  const float y1 = columns->StartPosY;
12912  const float y2 = window->DC.CursorPos.y;
12913  int dragging_column = -1;
12914  for (int n = 1; n < columns->Count; n++)
12915  {
12916  float x = window->Pos.x + GetColumnOffset(n);
12917  const ImGuiID column_id = columns->ID + ImGuiID(n);
12918  const float column_hw = GetColumnsRectHalfWidth(); // Half-width for interaction
12919  const ImRect column_rect(ImVec2(x - column_hw, y1), ImVec2(x + column_hw, y2));
12920  KeepAliveID(column_id);
12921  if (IsClippedEx(column_rect, column_id, false))
12922  continue;
12923 
12924  bool hovered = false, held = false;
12925  if (!(columns->Flags & ImGuiColumnsFlags_NoResize))
12926  {
12927  ButtonBehavior(column_rect, column_id, &hovered, &held);
12928  if (hovered || held)
12930  if (held && !(columns->Columns[n].Flags & ImGuiColumnsFlags_NoResize))
12931  dragging_column = n;
12932  }
12933 
12934  // Draw column (we clip the Y boundaries CPU side because very long triangles are mishandled by some GPU drivers.)
12936  const float xi = (float)(int)x;
12937  window->DrawList->AddLine(ImVec2(xi, ImMax(y1 + 1.0f, window->ClipRect.Min.y)), ImVec2(xi, ImMin(y2, window->ClipRect.Max.y)), col);
12938  }
12939 
12940  // Apply dragging after drawing the column lines, so our rendered lines are in sync with how items were displayed during the frame.
12941  if (dragging_column != -1)
12942  {
12943  if (!columns->IsBeingResized)
12944  for (int n = 0; n < columns->Count + 1; n++)
12945  columns->Columns[n].OffsetNormBeforeResize = columns->Columns[n].OffsetNorm;
12946  columns->IsBeingResized = is_being_resized = true;
12947  float x = GetDraggedColumnOffset(columns, dragging_column);
12948  SetColumnOffset(dragging_column, x);
12949  }
12950  }
12951  columns->IsBeingResized = is_being_resized;
12952 
12953  window->DC.ColumnsSet = NULL;
12954  window->DC.ColumnsOffsetX = 0.0f;
12955  window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX);
12956 }
12957 
12958 // [2018-03: This is currently the only public API, while we are working on making BeginColumns/EndColumns user-facing]
12959 void ImGui::Columns(int columns_count, const char* id, bool border)
12960 {
12961  ImGuiWindow* window = GetCurrentWindow();
12962  IM_ASSERT(columns_count >= 1);
12963 
12964  ImGuiColumnsFlags flags = (border ? 0 : ImGuiColumnsFlags_NoBorder);
12965  //flags |= ImGuiColumnsFlags_NoPreserveWidths; // NB: Legacy behavior
12966  if (window->DC.ColumnsSet != NULL && window->DC.ColumnsSet->Count == columns_count && window->DC.ColumnsSet->Flags == flags)
12967  return;
12968 
12969  if (window->DC.ColumnsSet != NULL)
12970  EndColumns();
12971 
12972  if (columns_count != 1)
12973  BeginColumns(id, columns_count, flags);
12974 }
12975 
12976 void ImGui::Indent(float indent_w)
12977 {
12978  ImGuiContext& g = *GImGui;
12979  ImGuiWindow* window = GetCurrentWindow();
12980  window->DC.IndentX += (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing;
12981  window->DC.CursorPos.x = window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX;
12982 }
12983 
12984 void ImGui::Unindent(float indent_w)
12985 {
12986  ImGuiContext& g = *GImGui;
12987  ImGuiWindow* window = GetCurrentWindow();
12988  window->DC.IndentX -= (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing;
12989  window->DC.CursorPos.x = window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX;
12990 }
12991 
12992 void ImGui::TreePush(const char* str_id)
12993 {
12994  ImGuiWindow* window = GetCurrentWindow();
12995  Indent();
12996  window->DC.TreeDepth++;
12997  PushID(str_id ? str_id : "#TreePush");
12998 }
12999 
13000 void ImGui::TreePush(const void* ptr_id)
13001 {
13002  ImGuiWindow* window = GetCurrentWindow();
13003  Indent();
13004  window->DC.TreeDepth++;
13005  PushID(ptr_id ? ptr_id : (const void*)"#TreePush");
13006 }
13007 
13009 {
13010  ImGuiWindow* window = GetCurrentWindow();
13011  Indent();
13012  window->DC.TreeDepth++;
13013  window->IDStack.push_back(id);
13014 }
13015 
13017 {
13018  ImGuiContext& g = *GImGui;
13019  ImGuiWindow* window = g.CurrentWindow;
13020  Unindent();
13021 
13022  window->DC.TreeDepth--;
13023  if (g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet())
13024  if (g.NavIdIsAlive && (window->DC.TreeDepthMayJumpToParentOnPop & (1 << window->DC.TreeDepth)))
13025  {
13026  SetNavID(window->IDStack.back(), g.NavLayer);
13028  }
13029  window->DC.TreeDepthMayJumpToParentOnPop &= (1 << window->DC.TreeDepth) - 1;
13030 
13031  PopID();
13032 }
13033 
13034 void ImGui::Value(const char* prefix, bool b)
13035 {
13036  Text("%s: %s", prefix, (b ? "true" : "false"));
13037 }
13038 
13039 void ImGui::Value(const char* prefix, int v)
13040 {
13041  Text("%s: %d", prefix, v);
13042 }
13043 
13044 void ImGui::Value(const char* prefix, unsigned int v)
13045 {
13046  Text("%s: %d", prefix, v);
13047 }
13048 
13049 void ImGui::Value(const char* prefix, float v, const char* float_format)
13050 {
13051  if (float_format)
13052  {
13053  char fmt[64];
13054  ImFormatString(fmt, IM_ARRAYSIZE(fmt), "%%s: %s", float_format);
13055  Text(fmt, prefix, v);
13056  }
13057  else
13058  {
13059  Text("%s: %.3f", prefix, v);
13060  }
13061 }
13062 
13063 //-----------------------------------------------------------------------------
13064 // DRAG AND DROP
13065 //-----------------------------------------------------------------------------
13066 
13068 {
13069  ImGuiContext& g = *GImGui;
13070  g.DragDropActive = false;
13071  g.DragDropPayload.Clear();
13073  g.DragDropAcceptIdCurrRectSurface = FLT_MAX;
13074  g.DragDropAcceptFrameCount = -1;
13075 }
13076 
13077 // Call when current ID is active.
13078 // When this returns true you need to: a) call SetDragDropPayload() exactly once, b) you may render the payload visual/description, c) call EndDragDropSource()
13080 {
13081  ImGuiContext& g = *GImGui;
13082  ImGuiWindow* window = g.CurrentWindow;
13083 
13084  bool source_drag_active = false;
13085  ImGuiID source_id = 0;
13086  ImGuiID source_parent_id = 0;
13087  int mouse_button = 0;
13088  if (!(flags & ImGuiDragDropFlags_SourceExtern))
13089  {
13090  source_id = window->DC.LastItemId;
13091  if (source_id != 0 && g.ActiveId != source_id) // Early out for most common case
13092  return false;
13093  if (g.IO.MouseDown[mouse_button] == false)
13094  return false;
13095 
13096  if (source_id == 0)
13097  {
13098  // If you want to use BeginDragDropSource() on an item with no unique identifier for interaction, such as Text() or Image(), you need to:
13099  // A) Read the explanation below, B) Use the ImGuiDragDropFlags_SourceAllowNullID flag, C) Swallow your programmer pride.
13100  if (!(flags & ImGuiDragDropFlags_SourceAllowNullID))
13101  {
13102  IM_ASSERT(0);
13103  return false;
13104  }
13105 
13106  // Magic fallback (=somehow reprehensible) to handle items with no assigned ID, e.g. Text(), Image()
13107  // We build a throwaway ID based on current ID stack + relative AABB of items in window.
13108  // THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING OF THE WIDGET, so if your widget moves your dragging operation will be canceled.
13109  // We don't need to maintain/call ClearActiveID() as releasing the button will early out this function and trigger !ActiveIdIsAlive.
13110  bool is_hovered = (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect) != 0;
13111  if (!is_hovered && (g.ActiveId == 0 || g.ActiveIdWindow != window))
13112  return false;
13113  source_id = window->DC.LastItemId = window->GetIDFromRectangle(window->DC.LastItemRect);
13114  if (is_hovered)
13115  SetHoveredID(source_id);
13116  if (is_hovered && g.IO.MouseClicked[mouse_button])
13117  {
13118  SetActiveID(source_id, window);
13119  FocusWindow(window);
13120  }
13121  if (g.ActiveId == source_id) // Allow the underlying widget to display/return hovered during the mouse release frame, else we would get a flicker.
13122  g.ActiveIdAllowOverlap = is_hovered;
13123  }
13124  if (g.ActiveId != source_id)
13125  return false;
13126  source_parent_id = window->IDStack.back();
13127  source_drag_active = IsMouseDragging(mouse_button);
13128  }
13129  else
13130  {
13131  window = NULL;
13132  source_id = ImHash("#SourceExtern", 0);
13133  source_drag_active = true;
13134  }
13135 
13136  if (source_drag_active)
13137  {
13138  if (!g.DragDropActive)
13139  {
13140  IM_ASSERT(source_id != 0);
13141  ClearDragDrop();
13142  ImGuiPayload& payload = g.DragDropPayload;
13143  payload.SourceId = source_id;
13144  payload.SourceParentId = source_parent_id;
13145  g.DragDropActive = true;
13147  g.DragDropMouseButton = mouse_button;
13148  }
13149 
13151  {
13152  // FIXME-DRAG
13153  //SetNextWindowPos(g.IO.MousePos - g.ActiveIdClickOffset - g.Style.WindowPadding);
13154  //PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * 0.60f); // This is better but e.g ColorButton with checkboard has issue with transparent colors :(
13157  BeginTooltip();
13158  }
13159 
13160  if (!(flags & ImGuiDragDropFlags_SourceNoDisableHover) && !(flags & ImGuiDragDropFlags_SourceExtern))
13162 
13163  return true;
13164  }
13165  return false;
13166 }
13167 
13169 {
13170  ImGuiContext& g = *GImGui;
13172 
13174  {
13175  EndTooltip();
13176  PopStyleColor();
13177  //PopStyleVar();
13178  }
13179 
13180  // Discard the drag if have not called SetDragDropPayload()
13181  if (g.DragDropPayload.DataFrameCount == -1)
13182  ClearDragDrop();
13183 }
13184 
13185 // Use 'cond' to choose to submit payload on drag start or every frame
13186 bool ImGui::SetDragDropPayload(const char* type, const void* data, size_t data_size, ImGuiCond cond)
13187 {
13188  ImGuiContext& g = *GImGui;
13189  ImGuiPayload& payload = g.DragDropPayload;
13190  if (cond == 0)
13191  cond = ImGuiCond_Always;
13192 
13193  IM_ASSERT(type != NULL);
13194  IM_ASSERT(strlen(type) < IM_ARRAYSIZE(payload.DataType) && "Payload type can be at most 12 characters long");
13195  IM_ASSERT((data != NULL && data_size > 0) || (data == NULL && data_size == 0));
13196  IM_ASSERT(cond == ImGuiCond_Always || cond == ImGuiCond_Once);
13197  IM_ASSERT(payload.SourceId != 0); // Not called between BeginDragDropSource() and EndDragDropSource()
13198 
13199  if (cond == ImGuiCond_Always || payload.DataFrameCount == -1)
13200  {
13201  // Copy payload
13202  ImStrncpy(payload.DataType, type, IM_ARRAYSIZE(payload.DataType));
13204  if (data_size > sizeof(g.DragDropPayloadBufLocal))
13205  {
13206  // Store in heap
13207  g.DragDropPayloadBufHeap.resize((int)data_size);
13208  payload.Data = g.DragDropPayloadBufHeap.Data;
13209  memcpy(payload.Data, data, data_size);
13210  }
13211  else if (data_size > 0)
13212  {
13213  // Store locally
13214  memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal));
13215  payload.Data = g.DragDropPayloadBufLocal;
13216  memcpy(payload.Data, data, data_size);
13217  }
13218  else
13219  {
13220  payload.Data = NULL;
13221  }
13222  payload.DataSize = (int)data_size;
13223  }
13224  payload.DataFrameCount = g.FrameCount;
13225 
13227 }
13228 
13230 {
13231  ImGuiContext& g = *GImGui;
13232  if (!g.DragDropActive)
13233  return false;
13234 
13235  ImGuiWindow* window = g.CurrentWindow;
13236  if (g.HoveredWindow == NULL || window->RootWindow != g.HoveredWindow->RootWindow)
13237  return false;
13238  IM_ASSERT(id != 0);
13239  if (!IsMouseHoveringRect(bb.Min, bb.Max) || (id == g.DragDropPayload.SourceId))
13240  return false;
13241 
13242  g.DragDropTargetRect = bb;
13243  g.DragDropTargetId = id;
13244  return true;
13245 }
13246 
13247 // We don't use BeginDragDropTargetCustom() and duplicate its code because:
13248 // 1) we use LastItemRectHoveredRect which handles items that pushes a temporarily clip rectangle in their code. Calling BeginDragDropTargetCustom(LastItemRect) would not handle them.
13249 // 2) and it's faster. as this code may be very frequently called, we want to early out as fast as we can.
13250 // Also note how the HoveredWindow test is positioned differently in both functions (in both functions we optimize for the cheapest early out case)
13252 {
13253  ImGuiContext& g = *GImGui;
13254  if (!g.DragDropActive)
13255  return false;
13256 
13257  ImGuiWindow* window = g.CurrentWindow;
13259  return false;
13260  if (g.HoveredWindow == NULL || window->RootWindow != g.HoveredWindow->RootWindow)
13261  return false;
13262 
13263  const ImRect& display_rect = (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect) ? window->DC.LastItemDisplayRect : window->DC.LastItemRect;
13264  ImGuiID id = window->DC.LastItemId;
13265  if (id == 0)
13266  id = window->GetIDFromRectangle(display_rect);
13267  if (g.DragDropPayload.SourceId == id)
13268  return false;
13269 
13270  g.DragDropTargetRect = display_rect;
13271  g.DragDropTargetId = id;
13272  return true;
13273 }
13274 
13276 {
13277  ImGuiContext& g = *GImGui;
13278  return g.DragDropActive && g.DragDropAcceptIdPrev != 0;
13279 }
13280 
13282 {
13283  ImGuiContext& g = *GImGui;
13284  ImGuiWindow* window = g.CurrentWindow;
13285  ImGuiPayload& payload = g.DragDropPayload;
13286  IM_ASSERT(g.DragDropActive); // Not called between BeginDragDropTarget() and EndDragDropTarget() ?
13287  IM_ASSERT(payload.DataFrameCount != -1); // Forgot to call EndDragDropTarget() ?
13288  if (type != NULL && !payload.IsDataType(type))
13289  return NULL;
13290 
13291  // Accept smallest drag target bounding box, this allows us to nest drag targets conveniently without ordering constraints.
13292  // NB: We currently accept NULL id as target. However, overlapping targets requires a unique ID to function!
13293  const bool was_accepted_previously = (g.DragDropAcceptIdPrev == g.DragDropTargetId);
13294  ImRect r = g.DragDropTargetRect;
13295  float r_surface = r.GetWidth() * r.GetHeight();
13296  if (r_surface < g.DragDropAcceptIdCurrRectSurface)
13297  {
13299  g.DragDropAcceptIdCurrRectSurface = r_surface;
13300  }
13301 
13302  // Render default drop visuals
13303  payload.Preview = was_accepted_previously;
13304  flags |= (g.DragDropSourceFlags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect); // Source can also inhibit the preview (useful for external sources that lives for 1 frame)
13305  if (!(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect) && payload.Preview)
13306  {
13307  // FIXME-DRAG: Settle on a proper default visuals for drop target.
13308  r.Expand(3.5f);
13309  bool push_clip_rect = !window->ClipRect.Contains(r);
13310  if (push_clip_rect) window->DrawList->PushClipRectFullScreen();
13311  window->DrawList->AddRect(r.Min, r.Max, GetColorU32(ImGuiCol_DragDropTarget), 0.0f, ~0, 2.0f);
13312  if (push_clip_rect) window->DrawList->PopClipRect();
13313  }
13314 
13316  payload.Delivery = was_accepted_previously && !IsMouseDown(g.DragDropMouseButton); // For extern drag sources affecting os window focus, it's easier to just test !IsMouseDown() instead of IsMouseReleased()
13317  if (!payload.Delivery && !(flags & ImGuiDragDropFlags_AcceptBeforeDelivery))
13318  return NULL;
13319 
13320  return &payload;
13321 }
13322 
13323 // We don't really use/need this now, but added it for the sake of consistency and because we might need it later.
13325 {
13326  ImGuiContext& g = *GImGui; (void)g;
13328 }
13329 
13330 //-----------------------------------------------------------------------------
13331 // PLATFORM DEPENDENT HELPERS
13332 //-----------------------------------------------------------------------------
13333 
13334 #if defined(_WIN32) && !defined(_WINDOWS_) && (!defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS) || !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS))
13335 #undef WIN32_LEAN_AND_MEAN
13336 #define WIN32_LEAN_AND_MEAN
13337 #ifndef __MINGW32__
13338 #include <Windows.h>
13339 #else
13340 #include <windows.h>
13341 #endif
13342 #endif
13343 
13344 // Win32 API clipboard implementation
13345 #if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS)
13346 
13347 #ifdef _MSC_VER
13348 #pragma comment(lib, "user32")
13349 #endif
13350 
13351 static const char* GetClipboardTextFn_DefaultImpl(void*)
13352 {
13353  static ImVector<char> buf_local;
13354  buf_local.clear();
13355  if (!OpenClipboard(NULL))
13356  return NULL;
13357  HANDLE wbuf_handle = GetClipboardData(CF_UNICODETEXT);
13358  if (wbuf_handle == NULL)
13359  {
13360  CloseClipboard();
13361  return NULL;
13362  }
13363  if (ImWchar* wbuf_global = (ImWchar*)GlobalLock(wbuf_handle))
13364  {
13365  int buf_len = ImTextCountUtf8BytesFromStr(wbuf_global, NULL) + 1;
13366  buf_local.resize(buf_len);
13367  ImTextStrToUtf8(buf_local.Data, buf_len, wbuf_global, NULL);
13368  }
13369  GlobalUnlock(wbuf_handle);
13370  CloseClipboard();
13371  return buf_local.Data;
13372 }
13373 
13374 static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
13375 {
13376  if (!OpenClipboard(NULL))
13377  return;
13378  const int wbuf_length = ImTextCountCharsFromUtf8(text, NULL) + 1;
13379  HGLOBAL wbuf_handle = GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(ImWchar));
13380  if (wbuf_handle == NULL)
13381  {
13382  CloseClipboard();
13383  return;
13384  }
13385  ImWchar* wbuf_global = (ImWchar*)GlobalLock(wbuf_handle);
13386  ImTextStrFromUtf8(wbuf_global, wbuf_length, text, NULL);
13387  GlobalUnlock(wbuf_handle);
13388  EmptyClipboard();
13389  SetClipboardData(CF_UNICODETEXT, wbuf_handle);
13390  CloseClipboard();
13391 }
13392 
13393 #else
13394 
13395 // Local ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers
13396 static const char* GetClipboardTextFn_DefaultImpl(void*)
13397 {
13398  ImGuiContext& g = *GImGui;
13399  return g.PrivateClipboard.empty() ? NULL : g.PrivateClipboard.begin();
13400 }
13401 
13402 // Local ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers
13403 static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
13404 {
13405  ImGuiContext& g = *GImGui;
13406  g.PrivateClipboard.clear();
13407  const char* text_end = text + strlen(text);
13408  g.PrivateClipboard.resize((int)(text_end - text) + 1);
13409  memcpy(&g.PrivateClipboard[0], text, (size_t)(text_end - text));
13410  g.PrivateClipboard[(int)(text_end - text)] = 0;
13411 }
13412 
13413 #endif
13414 
13415 // Win32 API IME support (for Asian languages, etc.)
13416 #if defined(_WIN32) && !defined(__GNUC__) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS)
13417 
13418 #include <imm.h>
13419 #ifdef _MSC_VER
13420 #pragma comment(lib, "imm32")
13421 #endif
13422 
13423 static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y)
13424 {
13425  // Notify OS Input Method Editor of text input position
13426  if (HWND hwnd = (HWND)GImGui->IO.ImeWindowHandle)
13427  if (HIMC himc = ImmGetContext(hwnd))
13428  {
13429  COMPOSITIONFORM cf;
13430  cf.ptCurrentPos.x = x;
13431  cf.ptCurrentPos.y = y;
13432  cf.dwStyle = CFS_FORCE_POSITION;
13433  ImmSetCompositionWindow(himc, &cf);
13434  }
13435 }
13436 
13437 #else
13438 
13439 static void ImeSetInputScreenPosFn_DefaultImpl(int, int) {}
13440 
13441 #endif
13442 
13443 //-----------------------------------------------------------------------------
13444 // HELP, METRICS
13445 //-----------------------------------------------------------------------------
13446 
13447 void ImGui::ShowMetricsWindow(bool* p_open)
13448 {
13449  if (ImGui::Begin("ImGui Metrics", p_open))
13450  {
13451  static bool show_draw_cmd_clip_rects = true;
13452  ImGui::Text("Dear ImGui %s", ImGui::GetVersion());
13453  ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
13454  ImGui::Text("%d vertices, %d indices (%d triangles)", ImGui::GetIO().MetricsRenderVertices, ImGui::GetIO().MetricsRenderIndices, ImGui::GetIO().MetricsRenderIndices / 3);
13455  ImGui::Text("%d allocations", (int)GImAllocatorActiveAllocationsCount);
13456  ImGui::Checkbox("Show clipping rectangles when hovering draw commands", &show_draw_cmd_clip_rects);
13457  ImGui::Separator();
13458 
13459  struct Funcs
13460  {
13461  static void NodeDrawList(ImGuiWindow* window, ImDrawList* draw_list, const char* label)
13462  {
13463  bool node_open = ImGui::TreeNode(draw_list, "%s: '%s' %d vtx, %d indices, %d cmds", label, draw_list->_OwnerName ? draw_list->_OwnerName : "", draw_list->VtxBuffer.Size, draw_list->IdxBuffer.Size, draw_list->CmdBuffer.Size);
13464  if (draw_list == ImGui::GetWindowDrawList())
13465  {
13466  ImGui::SameLine();
13467  ImGui::TextColored(ImColor(255,100,100), "CURRENTLY APPENDING"); // Can't display stats for active draw list! (we don't have the data double-buffered)
13468  if (node_open) ImGui::TreePop();
13469  return;
13470  }
13471 
13472  ImDrawList* overlay_draw_list = GetOverlayDrawList(); // Render additional visuals into the top-most draw list
13473  if (window && IsItemHovered())
13474  overlay_draw_list->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255));
13475  if (!node_open)
13476  return;
13477 
13478  int elem_offset = 0;
13479  for (const ImDrawCmd* pcmd = draw_list->CmdBuffer.begin(); pcmd < draw_list->CmdBuffer.end(); elem_offset += pcmd->ElemCount, pcmd++)
13480  {
13481  if (pcmd->UserCallback == NULL && pcmd->ElemCount == 0)
13482  continue;
13483  if (pcmd->UserCallback)
13484  {
13485  ImGui::BulletText("Callback %p, user_data %p", pcmd->UserCallback, pcmd->UserCallbackData);
13486  continue;
13487  }
13488  ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL;
13489  bool pcmd_node_open = ImGui::TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "Draw %4d %s vtx, tex 0x%p, clip_rect (%4.0f,%4.0f)-(%4.0f,%4.0f)", pcmd->ElemCount, draw_list->IdxBuffer.Size > 0 ? "indexed" : "non-indexed", pcmd->TextureId, pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w);
13490  if (show_draw_cmd_clip_rects && ImGui::IsItemHovered())
13491  {
13492  ImRect clip_rect = pcmd->ClipRect;
13493  ImRect vtxs_rect;
13494  for (int i = elem_offset; i < elem_offset + (int)pcmd->ElemCount; i++)
13495  vtxs_rect.Add(draw_list->VtxBuffer[idx_buffer ? idx_buffer[i] : i].pos);
13496  clip_rect.Floor(); overlay_draw_list->AddRect(clip_rect.Min, clip_rect.Max, IM_COL32(255,255,0,255));
13497  vtxs_rect.Floor(); overlay_draw_list->AddRect(vtxs_rect.Min, vtxs_rect.Max, IM_COL32(255,0,255,255));
13498  }
13499  if (!pcmd_node_open)
13500  continue;
13501 
13502  // Display individual triangles/vertices. Hover on to get the corresponding triangle highlighted.
13503  ImGuiListClipper clipper(pcmd->ElemCount/3); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible.
13504  while (clipper.Step())
13505  for (int prim = clipper.DisplayStart, vtx_i = elem_offset + clipper.DisplayStart*3; prim < clipper.DisplayEnd; prim++)
13506  {
13507  char buf[300];
13508  char *buf_p = buf, *buf_end = buf + IM_ARRAYSIZE(buf);
13509  ImVec2 triangles_pos[3];
13510  for (int n = 0; n < 3; n++, vtx_i++)
13511  {
13512  ImDrawVert& v = draw_list->VtxBuffer[idx_buffer ? idx_buffer[vtx_i] : vtx_i];
13513  triangles_pos[n] = v.pos;
13514  buf_p += ImFormatString(buf_p, (int)(buf_end - buf_p), "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n", (n == 0) ? "vtx" : " ", vtx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col);
13515  }
13516  ImGui::Selectable(buf, false);
13517  if (ImGui::IsItemHovered())
13518  {
13519  ImDrawListFlags backup_flags = overlay_draw_list->Flags;
13520  overlay_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines at is more readable for very large and thin triangles.
13521  overlay_draw_list->AddPolyline(triangles_pos, 3, IM_COL32(255,255,0,255), true, 1.0f);
13522  overlay_draw_list->Flags = backup_flags;
13523  }
13524  }
13525  ImGui::TreePop();
13526  }
13527  ImGui::TreePop();
13528  }
13529 
13530  static void NodeWindows(ImVector<ImGuiWindow*>& windows, const char* label)
13531  {
13532  if (!ImGui::TreeNode(label, "%s (%d)", label, windows.Size))
13533  return;
13534  for (int i = 0; i < windows.Size; i++)
13535  Funcs::NodeWindow(windows[i], "Window");
13536  ImGui::TreePop();
13537  }
13538 
13539  static void NodeWindow(ImGuiWindow* window, const char* label)
13540  {
13541  if (!ImGui::TreeNode(window, "%s '%s', %d @ 0x%p", label, window->Name, window->Active || window->WasActive, window))
13542  return;
13543  ImGuiWindowFlags flags = window->Flags;
13544  NodeDrawList(window, window->DrawList, "DrawList");
13545  ImGui::BulletText("Pos: (%.1f,%.1f), Size: (%.1f,%.1f), SizeContents (%.1f,%.1f)", window->Pos.x, window->Pos.y, window->Size.x, window->Size.y, window->SizeContents.x, window->SizeContents.y);
13546  ImGui::BulletText("Flags: 0x%08X (%s%s%s%s%s%s..)", flags,
13547  (flags & ImGuiWindowFlags_ChildWindow) ? "Child " : "", (flags & ImGuiWindowFlags_Tooltip) ? "Tooltip " : "", (flags & ImGuiWindowFlags_Popup) ? "Popup " : "",
13548  (flags & ImGuiWindowFlags_Modal) ? "Modal " : "", (flags & ImGuiWindowFlags_ChildMenu) ? "ChildMenu " : "", (flags & ImGuiWindowFlags_NoSavedSettings) ? "NoSavedSettings " : "");
13549  ImGui::BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f)", window->Scroll.x, GetScrollMaxX(window), window->Scroll.y, GetScrollMaxY(window));
13550  ImGui::BulletText("Active: %d, WriteAccessed: %d", window->Active, window->WriteAccessed);
13551  ImGui::BulletText("NavLastIds: 0x%08X,0x%08X, NavLayerActiveMask: %X", window->NavLastIds[0], window->NavLastIds[1], window->DC.NavLayerActiveMask);
13552  ImGui::BulletText("NavLastChildNavWindow: %s", window->NavLastChildNavWindow ? window->NavLastChildNavWindow->Name : "NULL");
13553  if (!window->NavRectRel[0].IsInverted())
13554  ImGui::BulletText("NavRectRel[0]: (%.1f,%.1f)(%.1f,%.1f)", window->NavRectRel[0].Min.x, window->NavRectRel[0].Min.y, window->NavRectRel[0].Max.x, window->NavRectRel[0].Max.y);
13555  else
13556  ImGui::BulletText("NavRectRel[0]: <None>");
13557  if (window->RootWindow != window) NodeWindow(window->RootWindow, "RootWindow");
13558  if (window->ParentWindow != NULL) NodeWindow(window->ParentWindow, "ParentWindow");
13559  if (window->DC.ChildWindows.Size > 0) NodeWindows(window->DC.ChildWindows, "ChildWindows");
13560  if (window->ColumnsStorage.Size > 0 && ImGui::TreeNode("Columns", "Columns sets (%d)", window->ColumnsStorage.Size))
13561  {
13562  for (int n = 0; n < window->ColumnsStorage.Size; n++)
13563  {
13564  const ImGuiColumnsSet* columns = &window->ColumnsStorage[n];
13565  if (ImGui::TreeNode((void*)(uintptr_t)columns->ID, "Columns Id: 0x%08X, Count: %d, Flags: 0x%04X", columns->ID, columns->Count, columns->Flags))
13566  {
13567  ImGui::BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->MaxX - columns->MinX, columns->MinX, columns->MaxX);
13568  for (int column_n = 0; column_n < columns->Columns.Size; column_n++)
13569  ImGui::BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", column_n, columns->Columns[column_n].OffsetNorm, OffsetNormToPixels(columns, columns->Columns[column_n].OffsetNorm));
13570  ImGui::TreePop();
13571  }
13572  }
13573  ImGui::TreePop();
13574  }
13575  ImGui::BulletText("Storage: %d bytes", window->StateStorage.Data.Size * (int)sizeof(ImGuiStorage::Pair));
13576  ImGui::TreePop();
13577  }
13578  };
13579 
13580  // Access private state, we are going to display the draw lists from last frame
13581  ImGuiContext& g = *GImGui;
13582  Funcs::NodeWindows(g.Windows, "Windows");
13583  if (ImGui::TreeNode("DrawList", "Active DrawLists (%d)", g.DrawDataBuilder.Layers[0].Size))
13584  {
13585  for (int i = 0; i < g.DrawDataBuilder.Layers[0].Size; i++)
13586  Funcs::NodeDrawList(NULL, g.DrawDataBuilder.Layers[0][i], "DrawList");
13587  ImGui::TreePop();
13588  }
13589  if (ImGui::TreeNode("Popups", "Open Popups Stack (%d)", g.OpenPopupStack.Size))
13590  {
13591  for (int i = 0; i < g.OpenPopupStack.Size; i++)
13592  {
13593  ImGuiWindow* window = g.OpenPopupStack[i].Window;
13594  ImGui::BulletText("PopupID: %08x, Window: '%s'%s%s", g.OpenPopupStack[i].PopupId, window ? window->Name : "NULL", window && (window->Flags & ImGuiWindowFlags_ChildWindow) ? " ChildWindow" : "", window && (window->Flags & ImGuiWindowFlags_ChildMenu) ? " ChildMenu" : "");
13595  }
13596  ImGui::TreePop();
13597  }
13598  if (ImGui::TreeNode("Internal state"))
13599  {
13600  const char* input_source_names[] = { "None", "Mouse", "Nav", "NavKeyboard", "NavGamepad" }; IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT);
13601  ImGui::Text("HoveredWindow: '%s'", g.HoveredWindow ? g.HoveredWindow->Name : "NULL");
13602  ImGui::Text("HoveredRootWindow: '%s'", g.HoveredRootWindow ? g.HoveredRootWindow->Name : "NULL");
13603  ImGui::Text("HoveredId: 0x%08X/0x%08X (%.2f sec)", g.HoveredId, g.HoveredIdPreviousFrame, g.HoveredIdTimer); // Data is "in-flight" so depending on when the Metrics window is called we may see current frame information or not
13604  ImGui::Text("ActiveId: 0x%08X/0x%08X (%.2f sec), ActiveIdSource: %s", g.ActiveId, g.ActiveIdPreviousFrame, g.ActiveIdTimer, input_source_names[g.ActiveIdSource]);
13605  ImGui::Text("ActiveIdWindow: '%s'", g.ActiveIdWindow ? g.ActiveIdWindow->Name : "NULL");
13606  ImGui::Text("MovingWindow: '%s'", g.MovingWindow ? g.MovingWindow->Name : "NULL");
13607  ImGui::Text("NavWindow: '%s'", g.NavWindow ? g.NavWindow->Name : "NULL");
13608  ImGui::Text("NavId: 0x%08X, NavLayer: %d", g.NavId, g.NavLayer);
13609  ImGui::Text("NavInputSource: %s", input_source_names[g.NavInputSource]);
13610  ImGui::Text("NavActive: %d, NavVisible: %d", g.IO.NavActive, g.IO.NavVisible);
13611  ImGui::Text("NavActivateId: 0x%08X, NavInputId: 0x%08X", g.NavActivateId, g.NavInputId);
13612  ImGui::Text("NavDisableHighlight: %d, NavDisableMouseHover: %d", g.NavDisableHighlight, g.NavDisableMouseHover);
13613  ImGui::Text("DragDrop: %d, SourceId = 0x%08X, Payload \"%s\" (%d bytes)", g.DragDropActive, g.DragDropPayload.SourceId, g.DragDropPayload.DataType, g.DragDropPayload.DataSize);
13614  ImGui::TreePop();
13615  }
13616  }
13617  ImGui::End();
13618 }
13619 
13620 //-----------------------------------------------------------------------------
13621 
13622 // Include imgui_user.inl at the end of imgui.cpp to access private data/functions that aren't exposed.
13623 // Prefer just including imgui_internal.h from your code rather than using this define. If a declaration is missing from imgui_internal.h add it or request it on the github.
13624 #ifdef IMGUI_INCLUDE_IMGUI_USER_INL
13625 #include "imgui_user.inl"
13626 #endif
13627 
13628 //-----------------------------------------------------------------------------
IMGUI_API bool BeginDragDropTarget()
Definition: imgui.cpp:13251
~ImGuiWindow()
Definition: imgui.cpp:2017
IMGUI_API void EndMenuBar()
Definition: imgui.cpp:11440
ImGuiCol Col
#define IMGUI_DEBUG_NAV_SCORING
Definition: imgui.cpp:679
IMGUI_API void SetScrollY(float scroll_y)
Definition: imgui.cpp:7331
ImGuiDir NavMoveDirLast
IMGUI_API ImVec2 GetItemRectMin()
Definition: imgui.cpp:4833
IMGUI_API ImGuiIO & GetIO()
Definition: imgui.cpp:2727
IMGUI_API void CaptureKeyboardFromApp(bool capture=true)
Definition: imgui.cpp:4767
int ImFormatString(char *buf, size_t buf_size, const char *fmt,...)
Definition: imgui.cpp:1124
IMGUI_API void SetNextWindowBgAlpha(float alpha)
Definition: imgui.cpp:7144
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t0
Definition: glcorearb.h:4876
IMGUI_API bool SliderInt3(const char *label, int v[3], int v_min, int v_max, const char *format="%d")
Definition: imgui.cpp:9227
bool WantSaveIniSettings
Definition: imgui.h:1120
ImVec2 BackupCursorPos
IMGUI_API void PushButtonRepeat(bool repeat)
Definition: imgui.cpp:6659
bool NavVisible
Definition: imgui.h:1122
IMGUI_API float GetWindowWidth()
Definition: imgui.cpp:6934
#define NAV_MAP_KEY(_KEY, _NAV_INPUT)
int FocusIdxTabRequestNext
float Framerate
Definition: imgui.h:1123
IMGUI_API float GetFrameHeightWithSpacing()
Definition: imgui.cpp:7209
int FocusIdxTabCounter
int(* ImGuiTextEditCallback)(ImGuiTextEditCallbackData *data)
Definition: imgui.h:105
IMGUI_API bool IsAnyItemHovered()
Definition: imgui.cpp:4799
bool HasSelection() const
void PathStroke(ImU32 col, bool closed, float thickness=1.0f)
Definition: imgui.h:1639
IMGUI_API float * GetFloatRef(ImGuiID key, float default_val=0.0f)
Definition: imgui.cpp:1619
ImGuiWindow * RootWindowForTitleBarHighlight
IMGUI_API bool IsMouseClicked(int button, bool repeat=false)
Definition: imgui.cpp:4670
IMGUI_API void RenderText(ImVec2 pos, const char *text, const char *text_end=NULL, bool hide_text_after_hash=true)
Definition: imgui.cpp:4290
ImRect NavInitResultRectRel
bool MouseDrawCursor
Definition: imgui.h:1098
float WindowBorderSize
IMGUI_API bool DragScalar(const char *label, ImGuiDataType data_type, void *v, float v_speed, const void *v_min=NULL, const void *v_max=NULL, const char *format=NULL, float power=1.0f)
Definition: imgui.cpp:9363
IMGUI_API bool VSliderInt(const char *label, const ImVec2 &size, int *v, int v_min, int v_max, const char *format="%d")
Definition: imgui.cpp:9173
IMGUI_API ImVec2 GetCursorPos()
Definition: imgui.cpp:7246
const char * ImParseFormatTrimDecorations(const char *fmt, char *buf, int buf_size)
Definition: imgui.cpp:8723
IMGUI_API bool SliderInt2(const char *label, int v[2], int v_min, int v_max, const char *format="%d")
Definition: imgui.cpp:9222
#define STB_TEXTEDIT_K_LINESTART
Definition: imgui.cpp:10005
IMGUI_API ImGuiContext * CreateContext(ImFontAtlas *shared_font_atlas=NULL)
Definition: imgui.cpp:2708
IMGUI_API bool IsAnyItemActive()
Definition: imgui.cpp:4805
ImVector< char > Buf
Definition: imgui.h:1311
IMGUI_API void TextUnformatted(const char *text, const char *text_end=NULL)
Definition: imgui.cpp:7464
int ActiveIdAllowNavDirFlags
ImGuiCond SetWindowPosAllowFlags
GLint GLenum GLint components
Definition: glcorearb.h:5268
#define IM_NEWLINE
Definition: imgui.cxx:894
IMGUI_API bool SliderFloat4(const char *label, float v[4], float v_min, float v_max, const char *format="%.3f", float power=1.0f)
Definition: imgui.cpp:9217
IMGUI_API bool SliderFloat(const char *label, float *v, float v_min, float v_max, const char *format="%.3f", float power=1.0f)
Definition: imgui.cpp:9101
#define IM_COL32_G_SHIFT
Definition: imgui.h:1444
IMGUI_API void SetNextWindowSize(const ImVec2 &size, ImGuiCond cond=0)
Definition: imgui.cpp:7106
ImVector< ImDrawCmd > CmdBuffer
Definition: imgui.h:1585
int ImGuiInputTextFlags
Definition: imgui.h:101
ImDrawVert * _VtxWritePtr
Definition: imgui.h:1594
IMGUI_API bool Button(const char *label, const ImVec2 &size=ImVec2(0, 0))
Definition: imgui.cpp:7799
IMGUI_API bool IsAnyMouseDown()
Definition: imgui.cpp:4661
ImVec2 GetCenter() const
const char * _OwnerName
Definition: imgui.h:1592
bool ActiveIdIsJustActivated
Double_t xi[28]
Definition: Geometry.cxx:51
bool MouseClicked[5]
Definition: imgui.h:1136
IMGUI_API void AddCircle(const ImVec2 &centre, float radius, ImU32 col, int num_segments=12, float thickness=1.0f)
IMGUI_API bool IsMouseDragging(int button=0, float lock_threshold=-1.0f)
Definition: imgui.cpp:4702
bool MouseDownOwned[5]
Definition: imgui.h:1139
ImVec2 GetBR() const
ImRect TitleBarRect() const
bool IsLoaded() const
Definition: imgui.h:1867
bool WantSetMousePos
Definition: imgui.h:1119
int ImTextCharFromUtf8(unsigned int *out_char, const char *in_text, const char *in_text_end)
Definition: imgui.cpp:1201
IMGUI_API ImVec4 ColorConvertU32ToFloat4(ImU32 in)
Definition: imgui.cpp:1370
IMGUI_API void AddRectFilledMultiColor(const ImVec2 &a, const ImVec2 &b, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left)
IMGUI_API void MarkIniSettingsDirty()
Definition: imgui.cpp:3922
IMGUI_API void RenderCheckMark(ImVec2 pos, ImU32 col, float sz)
Definition: imgui.cpp:4444
IMGUI_API bool IsMousePosValid(const ImVec2 *mouse_pos=NULL)
Definition: imgui.cpp:4728
IMGUI_API void SetVoidPtr(ImGuiID key, void *val)
Definition: imgui.cpp:1663
float ModalWindowDarkeningRatio
ImGuiWindow * ParentWindow
IMGUI_API void PushColumnClipRect(int column_index=-1)
Definition: imgui.cpp:12805
IMGUI_API void TreePop()
Definition: imgui.cpp:13016
if(clusterizer.getNClusters()< minNcl)
GLenum GLuint GLint GLint layer
Definition: glcorearb.h:1308
IMGUI_API void SetNextWindowSizeConstraints(const ImVec2 &size_min, const ImVec2 &size_max, ImGuiSizeCallback custom_callback=NULL, void *custom_callback_data=NULL)
Definition: imgui.cpp:7114
IMGUI_API ImVec2 CalcTextSize(const char *text, const char *text_end=NULL, bool hide_text_after_double_hash=false, float wrap_width=-1.0f)
Definition: imgui.cpp:4496
IMGUI_API void PopTextureID()
Definition: imgui_draw.cpp:479
void(* SetClipboardTextFn)(void *user_data, const char *text)
Definition: imgui.h:1073
ImVec2 ActiveIdClickOffset
IMGUI_API void ColorEditOptionsPopup(const float *col, ImGuiColorEditFlags flags)
Definition: imgui.cpp:11793
for(Int_t i=0;i< 6;i++)
Definition: Geometry.cxx:47
ImVec2 MousePos
Definition: imgui.h:1094
IMGUI_API void AddInputCharacter(ImWchar c)
Definition: imgui.cpp:943
ImVector< ImWchar > Text
IMGUI_API ImVec2 GetCursorScreenPos()
Definition: imgui.cpp:7291
ImDrawData DrawData
float MouseCursorScale
Definition: imgui.h:1021
IMGUI_API void PopClipRect()
Definition: imgui_draw.cpp:466
void OnKeyPressed(int key)
Definition: imgui.cpp:10022
Double_t xc2[28]
Definition: Geometry.cxx:76
IMGUI_API void ColorConvertHSVtoRGB(float h, float s, float v, float &out_r, float &out_g, float &out_b)
Definition: imgui.cpp:1446
IMGUI_API void DeleteChars(int pos, int bytes_count)
Definition: imgui.cpp:10032
void reserve(int capacity)
Definition: imgui.h:1320
IMGUI_API void LoadIniSettingsFromMemory(const char *ini_data, size_t ini_size=0)
Definition: imgui.cpp:3829
void Clear()
Definition: imgui.h:1349
IMGUI_API bool InputFloat(const char *label, float *v, float step=0.0f, float step_fast=0.0f, const char *format="%.3f", ImGuiInputTextFlags extra_flags=0)
Definition: imgui.cpp:10809
IMGUI_API void ClosePopupsOverWindow(ImGuiWindow *ref_window)
Definition: imgui.cpp:4952
IMGUI_API bool TreeNode(const char *label)
Definition: imgui.cpp:8368
IMGUI_API const char * GetStyleColorName(ImGuiCol idx)
Definition: imgui.cpp:6800
IMGUI_API const char * FindRenderedTextEnd(const char *text, const char *text_end=NULL)
Definition: imgui.cpp:4209
IMGUI_API void LogToTTY(int max_depth=-1)
Definition: imgui.cpp:7957
int WantCaptureMouseNextFrame
IMGUI_API ImGuiWindowSettings * FindWindowSettings(ImGuiID id)
Definition: imgui.cpp:3789
IMGUI_API ImU32 ColorConvertFloat4ToU32(const ImVec4 &in)
Definition: imgui.cpp:1380
IMGUI_API bool IsMouseDown(int button)
Definition: imgui.cpp:4654
IMGUI_API ImDrawList * GetOverlayDrawList()
Definition: imgui.cpp:2756
#define IM_COL32_R_SHIFT
Definition: imgui.h:1443
IMGUI_API bool IsWindowChildOf(ImGuiWindow *window, ImGuiWindow *potential_parent)
Definition: imgui.cpp:6852
IMGUI_API void ChannelsSetCurrent(int channel_index)
Definition: imgui_draw.cpp:553
IMGUI_API void Spacing()
Definition: imgui.cpp:12520
unsigned short ImDrawIdx
Definition: imgui.h:1530
IMGUI_API void SetTooltipV(const char *fmt, va_list args) IM_FMTLIST(1)
Definition: imgui.cpp:4877
IMGUI_API void PopItemFlag()
Definition: imgui.cpp:6642
void PathFillConvex(ImU32 col)
Definition: imgui.h:1638
IMGUI_API void appendf(const char *fmt,...) IM_FMTARGS(2)
Definition: imgui.cpp:1816
#define IM_COL32_BLACK
Definition: imgui.h:1451
IMGUI_API bool ListBox(const char *label, int *current_item, const char *const items[], int items_count, int height_in_items=-1)
Definition: imgui.cpp:11289
#define IM_ASSERT(_EXPR)
Definition: imgui.h:36
void * UserData
Definition: imgui.h:1052
bool ImTriangleContainsPoint(const ImVec2 &a, const ImVec2 &b, const ImVec2 &c, const ImVec2 &p)
Definition: imgui.cpp:984
ImGuiLayoutType LayoutType
#define IM_COL32_A_MASK
Definition: imgui.h:1447
IMGUI_API void split(char separator, ImVector< TextRange > &out)
Definition: imgui.cpp:1711
ImGuiID NavActivateId
const GLdouble * v
Definition: glcorearb.h:830
IMGUI_API ImGuiContext * GetCurrentContext()
Definition: imgui.cpp:2673
void resize(int new_size)
Definition: imgui.h:1230
IMGUI_API void EndMainMenuBar()
Definition: imgui.cpp:11399
int ImTextStrToUtf8(char *buf, int buf_size, const ImWchar *in_text, const ImWchar *in_text_end)
Definition: imgui.cpp:1340
int ImGuiDragDropFlags
Definition: imgui.h:98
IMGUI_API void SameLine(float pos_x=0.0f, float spacing_w=-1.0f)
Definition: imgui.cpp:12619
void * ImeWindowHandle
Definition: imgui.h:1079
float FontWindowScale
return false
unsigned char insert_mode
Definition: imgui.cxx:332
GLenum GLenum GLsizei len
Definition: glcorearb.h:4145
int ImStrlenW(const ImWchar *str)
Definition: imgui.cpp:1055
Definition: imgui.h:120
IMGUI_API void ListBoxFooter()
Definition: imgui.cpp:11273
GLuint start
Definition: glcorearb.h:468
float CurveTessellationTol
Definition: imgui.h:1024
void(* RenderDrawListsFn)(ImDrawData *data)
Definition: imgui.h:1084
IMGUI_API bool Combo(const char *label, int *current_item, const char *const items[], int items_count, int popup_max_height_in_items=-1)
Definition: imgui.cpp:11111
IMGUI_API bool DragFloatRange2(const char *label, float *v_current_min, float *v_current_max, float v_speed=1.0f, float v_min=0.0f, float v_max=0.0f, const char *format="%.3f", const char *format_max=NULL, float power=1.0f)
Definition: imgui.cpp:9484
int TooltipOverrideCount
IMGUI_API void PushMultiItemsWidths(int components, float width_full=0.0f)
Definition: imgui.cpp:6558
float MouseWheelH
Definition: imgui.h:1097
IMGUI_API void RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding=0.0f)
Definition: imgui.cpp:4387
bool ActiveIdAllowOverlap
IMGUI_API int GetKeyIndex(ImGuiKey imgui_key)
Definition: imgui.cpp:4600
float ChildBorderSize
Definition: imgui.h:1003
IMGUI_API bool BeginPopupContextItem(const char *str_id=NULL, int mouse_button=1)
Definition: imgui.cpp:5139
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
ImVec2 ScrollbarClickDeltaToGrabCenter
ImVec2 DisplaySize
Definition: imgui.h:1041
ImGuiInputTextFlags Flags
Definition: imgui.h:1379
IMGUI_API const ImFontGlyph * FindGlyph(ImWchar c) const
IMGUI_API float GetColumnOffset(int column_index=-1)
Definition: imgui.cpp:12733
ImGuiWindow * Window
int FramerateSecPerFrameIdx
IMGUI_API void CaptureMouseFromApp(bool capture=true)
Definition: imgui.cpp:4772
IMGUI_API void ClearFreeMemory()
Definition: imgui_draw.cpp:339
IMGUI_API void EndCombo()
Definition: imgui.cpp:11033
IMGUI_API bool IsItemFocused()
Definition: imgui.cpp:4788
IMGUI_API void SetMouseCursor(ImGuiMouseCursor type)
Definition: imgui.cpp:4762
IMGUI_API void AddInputCharactersUTF8(const char *utf8_chars)
Definition: imgui.cpp:953
IMGUI_API ImVec2 GetWindowContentRegionMin()
Definition: imgui.cpp:7173
ImVec2 ItemSpacing
Definition: imgui.h:1009
#define IM_COL32(R, G, B, A)
Definition: imgui.h:1449
IMGUI_API bool DragScalarN(const char *label, ImGuiDataType data_type, void *v, int components, float v_speed, const void *v_min=NULL, const void *v_max=NULL, const char *format=NULL, float power=1.0f)
Definition: imgui.cpp:9436
IMGUI_API void SetHoveredID(ImGuiID id)
Definition: imgui.cpp:2138
const char * ImStrchrRange(const char *str, const char *str_end, char c)
Definition: imgui.cpp:1047
ImGuiID HoveredId
GLboolean GLboolean g
Definition: glcorearb.h:1231
IMGUI_API ImVec2 GetMousePosOnOpeningCurrentPopup()
Definition: imgui.cpp:4719
bool Valid
Definition: imgui.h:1676
void *(* ReadOpenFn)(ImGuiContext *ctx, ImGuiSettingsHandler *handler, const char *name)
ImDrawList OverlayDrawList
int FocusIdxAllRequestCurrent
ImGuiNavMoveResult NavMoveResultLocal
float HoveredIdTimer
const ImFontGlyph * FallbackGlyph
Definition: imgui.h:1846
ImGuiID NavLastIds[2]
IMGUI_API void PushTextWrapPos(float wrap_pos_x=0.0f)
Definition: imgui.cpp:6669
int ImGuiWindowFlags
Definition: imgui.h:104
IMGUI_API void AddPolyline(const ImVec2 *points, const int num_points, ImU32 col, bool closed, float thickness)
Definition: imgui_draw.cpp:626
bool BackupActiveIdIsAlive
IMGUI_API void PushID(const char *str_id)
Definition: imgui.cpp:8398
IMGUI_API bool FocusableItemRegister(ImGuiWindow *window, ImGuiID id, bool tab_stop=true)
Definition: imgui.cpp:2583
IMGUI_API bool SetDragDropPayload(const char *type, const void *data, size_t size, ImGuiCond cond=0)
Definition: imgui.cpp:13186
IMGUI_API void SetTooltip(const char *fmt,...) IM_FMTARGS(1)
Definition: imgui.cpp:4884
IMGUI_API void EndDragDropTarget()
Definition: imgui.cpp:13324
IMGUI_API bool IsKeyDown(int user_key_index)
Definition: imgui.cpp:4607
ImVector< ImFontGlyph > Glyphs
Definition: imgui.h:1843
ImRect DragDropTargetRect
ImGuiWindow * RootWindowForNav
GLint GLint GLsizei GLint border
Definition: glcorearb.h:274
float TitleBarHeight() const
GLboolean GLboolean GLboolean GLboolean a
Definition: glcorearb.h:1231
bool IsInverted() const
IMGUI_API void SetNextWindowPos(const ImVec2 &pos, ImGuiCond cond=0, const ImVec2 &pivot=ImVec2(0, 0))
Definition: imgui.cpp:7097
IMGUI_API void SetWindowSize(const ImVec2 &size, ImGuiCond cond=0)
Definition: imgui.cpp:7034
int ImGuiDir
Definition: imgui.h:84
float KeysDownDurationPrev[512]
Definition: imgui.h:1145
IMGUI_API bool InputScalarN(const char *label, ImGuiDataType data_type, void *v, int components, const void *step=NULL, const void *step_fast=NULL, const char *format=NULL, ImGuiInputTextFlags extra_flags=0)
Definition: imgui.cpp:10828
IMGUI_API bool BeginChildFrame(ImGuiID id, const ImVec2 &size, ImGuiWindowFlags flags=0)
Definition: imgui.cpp:5267
IMGUI_API void Text(const char *fmt,...) IM_FMTARGS(1)
Definition: imgui.cpp:7410
IMGUI_API void SetScrollHere(float center_y_ratio=0.5f)
Definition: imgui.cpp:7348
int size() const
Definition: imgui.h:1317
ImVec2 ItemInnerSpacing
Definition: imgui.h:1010
float Descent
Definition: imgui.h:1854
ImVector< ImDrawIdx > IdxBuffer
Definition: imgui.h:1586
IMGUI_API void EndMenu()
Definition: imgui.cpp:11612
float FramerateSecPerFrameAccum
ImVector< ImGuiItemFlags > ItemFlagsStack
int KeyMap[ImGuiKey_COUNT]
Definition: imgui.h:1049
ImGuiColumnsSet * ColumnsSet
IMGUI_API void SetFocusID(ImGuiID id, ImGuiWindow *window)
Definition: imgui.cpp:2111
#define IM_F32_TO_INT8_SAT(_VAL)
Definition: imgui.cpp:969
IMGUI_API ImDrawData * GetDrawData()
Definition: imgui.cpp:2740
ImGuiAxis
IMGUI_API void SetCurrentContext(ImGuiContext *ctx)
Definition: imgui.cpp:2678
IMGUI_API void BuildSortByKey()
Definition: imgui.cpp:1560
IMGUI_API ImGuiID GetID(const char *str_id)
Definition: imgui.cpp:8429
ImGuiSizeCallback SizeCallback
IMGUI_API int GetFrameCount()
Definition: imgui.cpp:2751
IMGUI_API void PushFont(ImFont *font)
Definition: imgui.cpp:6614
IMGUI_API void PopStyleVar(int count=1)
Definition: imgui.cpp:6784
IMGUI_API void PathArcToFast(const ImVec2 &centre, float radius, int a_min_of_12, int a_max_of_12)
Definition: imgui_draw.cpp:886
void(* WriteAllFn)(ImGuiContext *ctx, ImGuiSettingsHandler *handler, ImGuiTextBuffer *out_buf)
IMGUI_API bool BeginMenu(const char *label, bool enabled=true)
Definition: imgui.cpp:11480
bool MouseReleased[5]
Definition: imgui.h:1138
IMGUI_API bool Draw(const char *label="Filter (inc,-exc)", float width=0.0f)
Definition: imgui.cpp:1699
ImFontAtlas * Fonts
Definition: imgui.h:1054
ImGuiID MoveId
IMGUI_API void ColorConvertRGBtoHSV(float r, float g, float b, float &out_h, float &out_s, float &out_v)
Definition: imgui.cpp:1424
IMGUI_API bool IsDragDropPayloadBeingAccepted()
Definition: imgui.cpp:13275
IMGUI_API float GetContentRegionAvailWidth()
Definition: imgui.cpp:7167
ImVec2 PlatformImePos
int CmdListsCount
Definition: imgui.h:1678
IMGUI_API void LogToClipboard(int max_depth=-1)
Definition: imgui.cpp:8001
IMGUI_API void ShowMetricsWindow(bool *p_open=NULL)
Definition: imgui.cpp:13447
ImVec2 DisplayVisibleMax
Definition: imgui.h:1060
IMGUI_API void PushTextureID(ImTextureID texture_id)
Definition: imgui_draw.cpp:473
IMGUI_API float GetTextLineHeightWithSpacing()
Definition: imgui.cpp:7197
#define STB_TEXTEDIT_K_UNDO
Definition: imgui.cpp:10011
ImGuiDragDropFlags DragDropSourceFlags
int BeginOrderWithinContext
#define IM_COL32_A_SHIFT
Definition: imgui.h:1446
GLenum GLenum GLsizei const GLuint GLboolean enabled
Definition: glcorearb.h:2548
bool FontAtlasOwnedByContext
ImGuiContext * GImGui
Definition: imgui.cpp:800
GLuint const GLchar * name
Definition: glcorearb.h:779
IMGUI_API bool * GetBoolRef(ImGuiID key, bool default_val=false)
Definition: imgui.cpp:1614
IMGUI_API void NextColumn()
Definition: imgui.cpp:12658
IMGUI_API bool DragInt4(const char *label, int v[4], float v_speed=1.0f, int v_min=0, int v_max=0, const char *format="%d")
Definition: imgui.cpp:9525
int ImGuiCond
Definition: imgui.h:85
#define STB_TEXTEDIT_K_TEXTEND
Definition: imgui.cpp:10008
IMGUI_API bool DragFloat4(const char *label, float v[4], float v_speed=1.0f, float v_min=0.0f, float v_max=0.0f, const char *format="%.3f", float power=1.0f)
Definition: imgui.cpp:9479
IMGUI_API bool IsKeyReleased(int user_key_index)
Definition: imgui.cpp:4646
IMGUI_API bool ImageButton(ImTextureID user_texture_id, const ImVec2 &size, const ImVec2 &uv0=ImVec2(0, 0), const ImVec2 &uv1=ImVec2(1, 1), int frame_padding=-1, const ImVec4 &bg_col=ImVec4(0, 0, 0, 0), const ImVec4 &tint_col=ImVec4(1, 1, 1, 1))
Definition: imgui.cpp:7920
GLfloat GLfloat GLfloat v2
Definition: glcorearb.h:811
IMGUI_API void PlotHistogram(const char *label, const float *values, int values_count, int values_offset=0, const char *overlay_text=NULL, float scale_min=FLT_MAX, float scale_max=FLT_MAX, ImVec2 graph_size=ImVec2(0, 0), int stride=sizeof(float))
Definition: imgui.cpp:9691
IMGUI_API void AddTriangleFilled(const ImVec2 &a, const ImVec2 &b, const ImVec2 &c, ImU32 col)
float BackupCurrentLineTextBaseOffset
IMGUI_API bool DragInt3(const char *label, int v[3], float v_speed=1.0f, int v_min=0, int v_max=0, const char *format="%d")
Definition: imgui.cpp:9520
ImVec2 SetWindowPosVal
ImGuiStorage StateStorage
ImRect NavScoringRectScreen
IMGUI_API ImVec2 GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor=0.0f, float fast_factor=0.0f)
Definition: imgui.cpp:2860
IMGUI_API void AddRect(const ImVec2 &a, const ImVec2 &b, ImU32 col, float rounding=0.0f, int rounding_corners_flags=ImDrawCornerFlags_All, float thickness=1.0f)
IMGUI_API void SetCurrentFont(ImFont *font)
Definition: imgui.cpp:6599
ImGuiItemFlags ItemFlags
ImVec2 DisplayVisibleMin
Definition: imgui.h:1059
int ImStricmp(const char *str1, const char *str2)
Definition: imgui.cpp:1019
char * ImStrdup(const char *str)
Definition: imgui.cpp:1040
GLuint * ids
Definition: glcorearb.h:645
IMGUI_API void PushStyleVar(ImGuiStyleVar idx, float val)
Definition: imgui.cpp:6756
unsigned char DragDropPayloadBufLocal[8]
IMGUI_API bool IsMouseDoubleClicked(int button)
Definition: imgui.cpp:4695
ImGuiPlotType
ImGuiInputReadMode
IMGUI_API bool IsItemHovered(ImGuiHoveredFlags flags=0)
Definition: imgui.cpp:2510
const char * begin() const
Definition: imgui.h:1287
ImGuiMenuColumns MenuColumns
int ImTextCountUtf8BytesFromStr(const ImWchar *in_text, const ImWchar *in_text_end)
Definition: imgui.cpp:1356
IMGUI_API bool SliderScalar(const char *label, ImGuiDataType data_type, void *v, const void *v_min, const void *v_max, const char *format=NULL, float power=1.0f)
Definition: imgui.cpp:9037
float WindowRounding
#define STB_TEXTEDIT_K_SHIFT
Definition: imgui.cpp:10015
ImVec2 ImTriangleClosestPoint(const ImVec2 &a, const ImVec2 &b, const ImVec2 &c, const ImVec2 &p)
Definition: imgui.cpp:1003
IMGUI_API void SetWindowCollapsed(bool collapsed, ImGuiCond cond=0)
Definition: imgui.cpp:7056
IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char *label, const char *label_end=NULL)
Definition: imgui.cpp:8111
IMGUI_API bool InputInt(const char *label, int *v, int step=1, int step_fast=100, ImGuiInputTextFlags extra_flags=0)
Definition: imgui.cpp:10821
IMGUI_API void AddLine(const ImVec2 &a, const ImVec2 &b, ImU32 col, float thickness=1.0f)
Definition: imgui_draw.cpp:991
ImVector< ImDrawVert > VtxBuffer
Definition: imgui.h:1587
ImGuiInputSource NavInputSource
IMGUI_API float GetFontSize()
Definition: imgui.cpp:7226
IMGUI_API void PushClipRect(ImVec2 clip_rect_min, ImVec2 clip_rect_max, bool intersect_with_current_clip_rect=false)
Definition: imgui_draw.cpp:443
float FrameRounding
Definition: imgui.h:1007
int ImGuiColorEditFlags
Definition: imgui.h:94
IMGUI_API bool IsWindowFocused(ImGuiFocusedFlags flags=0)
Definition: imgui.cpp:6906
bool WantCaptureKeyboard
Definition: imgui.h:1117
IMGUI_API void End()
Definition: imgui.cpp:6344
void * GetVarPtr(ImGuiStyle *style) const
Definition: imgui.cpp:6721
IMGUI_API void SetCursorPosY(float y)
Definition: imgui.cpp:7278
IMGUI_API bool InputScalar(const char *label, ImGuiDataType data_type, void *v, const void *step=NULL, const void *step_fast=NULL, const char *format=NULL, ImGuiInputTextFlags extra_flags=0)
Definition: imgui.cpp:10749
bool empty() const
Definition: imgui.h:1212
IMGUI_API void ** GetVoidPtrRef(ImGuiID key, void *default_val=NULL)
Definition: imgui.cpp:1627
while((z< zmin)||(z > zmax))
ImGuiColorEditFlags ColorEditOptions
IMGUI_API void Build()
Definition: imgui.cpp:1729
IMGUI_API void ClosePopup(ImGuiID id)
Definition: imgui.cpp:5006
IMGUI_API float GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode)
Definition: imgui.cpp:2821
#define STB_TEXTEDIT_K_REDO
Definition: imgui.cpp:10012
ImDrawList ** CmdLists
Definition: imgui.h:1677
ImVector< ImGuiWindow * > CurrentWindowStack
IMGUI_API bool IsItemClicked(int mouse_button=0)
Definition: imgui.cpp:4794
float NavInputs[ImGuiNavInput_COUNT]
Definition: imgui.h:1105
bool OptCursorBlink
Definition: imgui.h:1064
IMGUI_API ImDrawList * GetWindowDrawList()
Definition: imgui.cpp:7215
char InputBuf[256]
Definition: imgui.h:1296
iterator begin()
Definition: imgui.h:1219
ImVector< unsigned short > IndexLookup
Definition: imgui.h:1845
IMGUI_API bool BeginDragDropSource(ImGuiDragDropFlags flags=0)
Definition: imgui.cpp:13079
ImVector< ImFont * > FontStack
ImVec2 uv
Definition: imgui.h:1538
ImGuiID NavActivatePressedId
IMGUI_API void ActivateItem(ImGuiID id)
Definition: imgui.cpp:7356
IMGUI_API bool DragInt(const char *label, int *v, float v_speed=1.0f, int v_min=0, int v_max=0, const char *format="%d")
Definition: imgui.cpp:9510
IMGUI_API void SetKeyboardFocusHere(int offset=0)
Definition: imgui.cpp:7362
IMGUI_API ImGuiTextFilter(const char *default_filter="")
Definition: imgui.cpp:1685
bool empty() const
Definition: imgui.h:1289
float ColumnsMinSpacing
Definition: imgui.h:1013
float DeltaTime
Definition: imgui.h:1042
#define STB_TEXTEDIT_K_DOWN
Definition: imgui.cpp:10004
bool WantCaptureMouse
Definition: imgui.h:1116
IMGUI_API int GetColumnsCount()
Definition: imgui.cpp:12698
GLsizeiptr size
Definition: glcorearb.h:657
ImGuiWindow * RootWindowForTabbing
IMGUI_API void Clear()
Definition: imgui_draw.cpp:322
#define STB_TEXTEDIT_K_LINEEND
Definition: imgui.cpp:10006
#define STB_TEXTEDIT_GETWIDTH_NEWLINE
GLuint id
Definition: glcorearb.h:648
IMGUI_API void FlattenIntoSingleLayer()
Definition: imgui.cpp:4020
IMGUI_API bool SplitterBehavior(ImGuiID id, const ImRect &bb, ImGuiAxis axis, float *size1, float *size2, float min_size1, float min_size2, float hover_extend=0.0f)
Definition: imgui.cpp:12473
IMGUI_API bool BeginDragDropTargetCustom(const ImRect &bb, ImGuiID id)
Definition: imgui.cpp:13229
IMGUI_API void PopTextWrapPos()
Definition: imgui.cpp:6676
IMGUI_API bool DragFloat(const char *label, float *v, float v_speed=1.0f, float v_min=0.0f, float v_max=0.0f, const char *format="%.3f", float power=1.0f)
Definition: imgui.cpp:9464
ImDrawList * DrawList
ImVec2 SetWindowPosPivot
ImDrawDataBuilder DrawDataBuilder
ImGuiDrawContext DC
GLuint GLfloat GLfloat GLfloat GLfloat y1
Definition: glcorearb.h:4876
ImRect Rect() const
bool IsDataType(const char *type) const
Definition: imgui.h:1430
IMGUI_API ImGuiID GetHoveredID()
Definition: imgui.cpp:2146
IMGUI_API float GetCursorPosY()
Definition: imgui.cpp:7258
ImGuiWindow(ImGuiContext *context, const char *name)
Definition: imgui.cpp:1957
IMGUI_API void Indent(float indent_w=0.0f)
Definition: imgui.cpp:12976
bool NavActive
Definition: imgui.h:1121
IMGUI_API bool SliderFloat3(const char *label, float v[3], float v_min, float v_max, const char *format="%.3f", float power=1.0f)
Definition: imgui.cpp:9212
IMGUI_API bool PassFilter(const char *text, const char *text_end=NULL) const
Definition: imgui.cpp:1746
ImGuiDataType Type
Definition: imgui.cpp:6718
IMGUI_API void Unindent(float indent_w=0.0f)
Definition: imgui.cpp:12984
IMGUI_API bool OpenPopupOnItemClick(const char *str_id=NULL, int mouse_button=1)
Definition: imgui.cpp:5123
ImGuiID GetIDNoKeepAlive(const char *str, const char *str_end=NULL)
Definition: imgui.cpp:2041
void Clear()
Definition: imgui.h:1685
ImGuiID ActiveId
#define IM_NEW(_TYPE)
Definition: imgui.h:1260
IMGUI_API bool ArrowButton(const char *str_id, ImGuiDir dir)
Definition: imgui.cpp:7815
void pop_back()
Definition: imgui.h:1246
IMGUI_API void DestroyContext(ImGuiContext *ctx=NULL)
Definition: imgui.cpp:2717
int Size
Definition: imgui.h:1199
ImRect MenuBarRect() const
IMGUI_API bool DragIntRange2(const char *label, int *v_current_min, int *v_current_max, float v_speed=1.0f, int v_min=0, int v_max=0, const char *format="%d", const char *format_max=NULL)
Definition: imgui.cpp:9530
ImGuiID GetIDFromRectangle(const ImRect &r_abs)
Definition: imgui.cpp:2048
IMGUI_API void PopAllowKeyboardFocus()
Definition: imgui.cpp:6654
GLdouble n
Definition: glcorearb.h:2017
int ImGuiHoveredFlags
Definition: imgui.h:100
IMGUI_API void RenderRectFilledRangeH(ImDrawList *draw_list, const ImRect &rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding)
IMGUI_API bool VSliderFloat(const char *label, const ImVec2 &size, float *v, float v_min, float v_max, const char *format="%.3f", float power=1.0f)
Definition: imgui.cpp:9168
IMGUI_API bool BeginChild(const char *str_id, const ImVec2 &size=ImVec2(0, 0), bool border=false, ImGuiWindowFlags flags=0)
Definition: imgui.cpp:5215
void * ImFileLoadToMemory(const char *filename, const char *file_open_mode, size_t *out_file_size, int padding_bytes)
Definition: imgui.cpp:1491
float CurrentLineTextBaseOffset
GLfloat f
Definition: glcorearb.h:1935
IMGUI_API void SetFloat(ImGuiID key, float val)
Definition: imgui.cpp:1652
ImGuiInputTextFlags EventFlag
Definition: imgui.h:1378
float DragSpeedDefaultRatio
ClassImp(o2::ITSMFT::Cluster) void Cluster printf("XYZ: %+.4e %+.4e %+.4e\n", getX(), getY(), getZ())
IMGUI_API void * MemAlloc(size_t size)
Definition: imgui.cpp:2643
ImVec2 DisplayOffset
Definition: imgui.h:1842
IMGUI_API void LabelTextV(const char *label, const char *fmt, va_list args) IM_FMTLIST(2)
Definition: imgui.cpp:7582
#define IMGUI_CDECL
Definition: imgui.cpp:714
IMGUI_API void SetWindowPos(const ImVec2 &pos, ImGuiCond cond=0)
Definition: imgui.cpp:6984
IMGUI_API void RenderArrow(ImVec2 pos, ImGuiDir dir, float scale=1.0f)
Definition: imgui.cpp:4400
IMGUI_API void Bullet()
Definition: imgui.cpp:8444
#define IM_COL32_BLACK_TRANS
Definition: imgui.h:1452
ImGuiWindow * NavLastChildNavWindow
ImVector< ImGuiWindow * > Windows
IMGUI_API bool IsPopupOpen(const char *str_id)
Definition: imgui.cpp:5065
IMGUI_API void SetClipboardText(const char *text)
Definition: imgui.cpp:2660
IMGUI_API bool IsMouseHoveringRect(const ImVec2 &r_min, const ImVec2 &r_max, bool clip=true)
Definition: imgui.cpp:4580
IMGUI_API bool DragBehavior(ImGuiID id, ImGuiDataType data_type, void *v, float v_speed, const void *v_min, const void *v_max, const char *format, float power)
Definition: imgui.cpp:9336
int WantTextInputNextFrame
ImVector< ImVec4 > _ClipRectStack
Definition: imgui.h:1596
bool NavWindowingToggleLayer
IMGUI_API bool SliderAngle(const char *label, float *v_rad, float v_degrees_min=-360.0f, float v_degrees_max=+360.0f)
Definition: imgui.cpp:9155
int DataFrameCount
Definition: imgui.h:1423
float FontSize
Definition: imgui.h:1840
ImVec2 SizeContentsExplicit
ImGuiNavForward NavMoveRequestForward
float Alpha
Definition: imgui.h:996
ImGuiID GetID(const char *str, const char *str_end=NULL)
Definition: imgui.cpp:2025
unsigned int ImU32
Definition: imgui.h:110
ImGuiStb::STB_TexteditState StbState
IMGUI_API void AlignTextToFramePadding()
Definition: imgui.cpp:7570
IMGUI_API void AddTriangle(const ImVec2 &a, const ImVec2 &b, const ImVec2 &c, ImU32 col, float thickness=1.0f)
IMGUI_API void MemFree(void *ptr)
Definition: imgui.cpp:2649
const char * ImParseFormatFindStart(const char *fmt)
Definition: imgui.cpp:8688
IMGUI_API void KeepAliveID(ImGuiID id)
Definition: imgui.cpp:2152
IMGUI_API float GetTextLineHeight()
Definition: imgui.cpp:7191
void Expand(const float amount)
ImVector< char > TempTextBuffer
IMGUI_API bool DebugCheckVersionAndDataLayout(const char *version_str, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_drawvert)
Definition: imgui.cpp:2689
int ImTextStrFromUtf8(ImWchar *buf, int buf_size, const char *in_text, const char *in_text_end, const char **in_text_remaining)
Definition: imgui.cpp:1259
IMGUI_API bool ColorEdit3(const char *label, float col[3], ImGuiColorEditFlags flags=0)
Definition: imgui.cpp:11788
const char * ImStristr(const char *haystack, const char *haystack_end, const char *needle, const char *needle_end)
Definition: imgui.cpp:1069
ImGuiID OpenParentId
IMGUI_API ImGuiStyle & GetStyle()
Definition: imgui.cpp:2733
char front() const
Definition: imgui.h:1290
float MouseDownDurationPrev[5]
Definition: imgui.h:1141
IMGUI_API void NewFrameUpdateHoveredWindowAndCaptureFlags()
Definition: imgui.cpp:3406
float w
Definition: imgui.h:134
ImFont InputTextPasswordFont
int DisplayStart
Definition: imgui.h:1492
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t1
Definition: glcorearb.h:4876
bool NavInitRequestFromMove
GLint GLsizei count
Definition: glcorearb.h:398
const char * ImParseFormatFindEnd(const char *fmt)
Definition: imgui.cpp:8701
ImGuiColumnsFlags Flags
IMGUI_API void Render()
Definition: imgui.cpp:4157
IMGUI_API bool Step()
Definition: imgui.cpp:1916
void ClipWith(const ImRect &r)
ImVec2 SizeFullAtLastBegin
ImVec2 WindowMinSize
Definition: imgui.h:1000
IMGUI_API void SetScrollFromPosY(float pos_y, float center_y_ratio=0.5f)
Definition: imgui.cpp:7338
IMGUI_API void PushItemWidth(float item_width)
Definition: imgui.cpp:6551
constexpr float dy
IMGUI_API bool ColorEdit4(const char *label, float col[4], ImGuiColorEditFlags flags=0)
Definition: imgui.cpp:11882
ImGuiTextEditState InputTextState
IMGUI_API void ColorTooltip(const char *text, const float *col, ImGuiColorEditFlags flags)
Definition: imgui.cpp:11629
ImGuiID NavJustTabbedId
IMGUI_API void SetItemDefaultFocus()
Definition: imgui.cpp:7370
bool CollapseToggleWanted
bool Preview
Definition: imgui.h:1425
IMGUI_API void TreePushRawID(ImGuiID id)
Definition: imgui.cpp:13008
IMGUI_API void PushItemFlag(ImGuiItemFlags option, bool enabled)
Definition: imgui.cpp:6632
IMGUI_API void SetAllocatorFunctions(void *(*alloc_func)(size_t sz, void *user_data), void(*free_func)(void *ptr, void *user_data), void *user_data=NULL)
Definition: imgui.cpp:2701
ImGuiWindow * RootWindow
IMGUI_API bool Checkbox(const char *label, bool *v)
Definition: imgui.cpp:9738
ImU32 ImHash(const void *data, int data_size, ImU32 seed)
Definition: imgui.cpp:1152
ImVector< ImGuiColMod > ColorModifiers
IMGUI_API int GetKeyPressedAmount(int key_index, float repeat_delay, float rate)
Definition: imgui.cpp:4624
IMGUI_API bool BeginPopupContextWindow(const char *str_id=NULL, int mouse_button=1, bool also_over_items=true)
Definition: imgui.cpp:5149
IMGUI_API void Scrollbar(ImGuiLayoutType direction)
Definition: imgui.cpp:6370
void swap(ImVector< value_type > &rhs)
Definition: imgui.h:1227
ImVec2 Max
IMGUI_API float GetWindowHeight()
Definition: imgui.cpp:6940
IMGUI_API void SetColorEditOptions(ImGuiColorEditFlags flags)
Definition: imgui.cpp:11698
IMGUI_API const char * GetVersion()
Definition: imgui.cpp:2666
IMGUI_API float GetCursorPosX()
Definition: imgui.cpp:7252
void push_front(const value_type &v)
Definition: imgui.h:1247
#define IM_STATIC_ASSERT(_COND)
Definition: imgui.cpp:967
#define IMGUI_PAYLOAD_TYPE_COLOR_4F
Definition: imgui.h:725
float ItemWidthDefault
IMGUI_API void FocusWindow(ImGuiWindow *window)
Definition: imgui.cpp:6505
IMGUI_API bool BeginPopup(const char *str_id, ImGuiWindowFlags flags=0)
Definition: imgui.cpp:5048
ImGuiWindow * ActiveIdWindow
IMGUI_API ImGuiStorage * GetStateStorage()
Definition: imgui.cpp:7393
GLuint GLuint end
Definition: glcorearb.h:468
ImGuiTextBuffer SettingsIniData
bool AutoFitOnlyGrows
float ChildRounding
Definition: imgui.h:1002
ImGuiWindow * NavWindowingTarget
ImVector< ImGuiStyleMod > StyleModifiers
IMGUI_API void RenderNavHighlight(const ImRect &bb, ImGuiID id, ImGuiNavHighlightFlags flags=ImGuiNavHighlightFlags_TypeDefault)
Definition: imgui.cpp:4462
IMGUI_API void AddText(const ImVec2 &pos, ImU32 col, const char *text_begin, const char *text_end=NULL)
bool Contains(const ImVec2 &p) const
IMGUI_API bool RadioButton(const char *label, bool active)
Definition: imgui.cpp:9802
ImGuiDir AutoPosLastDirection
bool DragCurrentAccumDirty
IMGUI_API bool BeginMainMenuBar()
Definition: imgui.cpp:11379
ImRect ContentsRegionRect
ImDrawListSharedData DrawListSharedData
IMGUI_API float CalcItemWidth()
Definition: imgui.cpp:6579
ImGuiID HoveredIdPreviousFrame
IMGUI_API const ImGuiPayload * AcceptDragDropPayload(const char *type, ImGuiDragDropFlags flags=0)
Definition: imgui.cpp:13281
IMGUI_API bool ItemAdd(const ImRect &bb, ImGuiID id, const ImRect *nav_bb=NULL)
Definition: imgui.cpp:2472
float MouseDoubleClickTime
Definition: imgui.h:1046
float GrabMinSize
Definition: imgui.h:1016
GLuint GLsizei const GLchar * label
Definition: glcorearb.h:2554
ImGuiID DragDropTargetId
ImGuiID SourceId
Definition: imgui.h:1421
IMGUI_API void PopStyleColor(int count=1)
Definition: imgui.cpp:6704
void ImTriangleBarycentricCoords(const ImVec2 &a, const ImVec2 &b, const ImVec2 &c, const ImVec2 &p, float &out_u, float &out_v, float &out_w)
Definition: imgui.cpp:992
ImVector< ImGuiColumnData > Columns
auto dot(const Vertex< T > &a, const Vertex< T > &b) -> decltype(a.x *b.x)
Definition: Vertex.h:103
IMGUI_API bool ColorPicker4(const char *label, float col[4], ImGuiColorEditFlags flags=0, const float *ref_col=NULL)
Definition: imgui.cpp:12114
IMGUI_API void BeginTooltip()
Definition: imgui.cpp:4892
int MetricsRenderIndices
Definition: imgui.h:1125
IMGUI_API void EndTooltip()
Definition: imgui.cpp:4897
float GetWidth() const
int DataSize
Definition: imgui.h:1418
IMGUI_API bool IsAnyItemFocused()
Definition: imgui.cpp:4811
IMGUI_API void Shutdown(ImGuiContext *context)
Definition: imgui.cpp:3733
IMGUI_API ImGuiWindow * GetFrontMostPopupModal()
Definition: imgui.cpp:4984
float z
Definition: imgui.h:134
ImVec2 WindowPadding
GLboolean * data
Definition: glcorearb.h:297
IMGUI_API ImVec2 GetContentRegionMax()
Definition: imgui.cpp:7152
IMGUI_API bool IsWindowNavFocusable(ImGuiWindow *window)
Definition: imgui.cpp:6928
ImGuiID NavInitResultId
IMGUI_API void ShadeVertsLinearColorGradientKeepAlpha(ImDrawVert *vert_start, ImDrawVert *vert_end, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1)
const char * c_str() const
Definition: imgui.h:1321
IMGUI_API ImVec2 GetItemRectMax()
Definition: imgui.cpp:4839
IMGUI_API void SetWindowFocus()
Definition: imgui.cpp:7079
#define IM_F32_TO_INT8_UNBOUND(_VAL)
Definition: imgui.cpp:968
float NavInputsDownDuration[ImGuiNavInput_COUNT]
Definition: imgui.h:1146
IMGUI_API void ChannelsMerge()
Definition: imgui_draw.cpp:519
int ImGuiStyleVar
Definition: imgui.h:89
ImGuiID ActiveIdPreviousFrame
IMGUI_API void VerticalSeparator()
Definition: imgui.cpp:12454
IMGUI_API ImVec2 GetCursorStartPos()
Definition: imgui.cpp:7285
void ImStrncpy(char *dst, const char *src, size_t count)
Definition: imgui.cpp:1033
GLint first
Definition: glcorearb.h:398
IMGUI_API float GetTime()
Definition: imgui.cpp:2746
IMGUI_API bool SliderFloat2(const char *label, float v[2], float v_min, float v_max, const char *format="%.3f", float power=1.0f)
Definition: imgui.cpp:9207
void * ClipboardUserData
Definition: imgui.h:1074
void reserve(int new_capacity)
Definition: imgui.h:1232
float ScrollbarRounding
Definition: imgui.h:1015
const char * ScanFmt
Definition: imgui.cpp:8552
GLint GLsizei width
Definition: glcorearb.h:269
IMGUI_API void TextColoredV(const ImVec4 &col, const char *fmt, va_list args) IM_FMTLIST(2)
Definition: imgui.cpp:7418
float GetHeight() const
IMGUI_API ImVec2 GetWindowSize()
Definition: imgui.cpp:6996
GLfloat GLfloat GLfloat alpha
Definition: glcorearb.h:278
IMGUI_API void Initialize(ImGuiContext *context)
Definition: imgui.cpp:3715
IMGUI_API int GetInt(ImGuiID key, int default_val=0) const
Definition: imgui.cpp:1576
IMGUI_API bool SliderInt4(const char *label, int v[4], int v_min, int v_max, const char *format="%d")
Definition: imgui.cpp:9232
unsigned long long ImU64
Definition: imgui.h:116
IMGUI_API bool CheckboxFlags(const char *label, unsigned int *flags, unsigned int flags_value)
Definition: imgui.cpp:9787
bool KeyShift
Definition: imgui.h:1100
const char * IniFilename
Definition: imgui.h:1044
int ImTextCountCharsFromUtf8(const char *in_text, const char *in_text_end)
Definition: imgui.cpp:1278
float CalcFontSize() const
GLenum GLsizei GLsizei GLint * values
Definition: glcorearb.h:1611
IMGUI_API void SetCursorScreenPos(const ImVec2 &screen_pos)
Definition: imgui.cpp:7297
float PopupBorderSize
Definition: imgui.h:1005
int ImGuiTreeNodeFlags
Definition: imgui.h:103
ImVector< ImGuiWindowSettings > SettingsWindows
IMGUI_API void AddImage(ImTextureID user_texture_id, const ImVec2 &a, const ImVec2 &b, const ImVec2 &uv_a=ImVec2(0, 0), const ImVec2 &uv_b=ImVec2(1, 1), ImU32 col=0xFFFFFFFF)
IMGUI_API void EndChildFrame()
Definition: imgui.cpp:5278
IMGUI_API void SetColumnWidth(int column_index, float width)
Definition: imgui.cpp:12794
ImVec2 ScrollTargetCenterRatio
ImU32 col
Definition: imgui.h:1539
ImGuiWindow * HoveredRootWindow
IMGUI_API ImVec2 GetContentRegionAvail()
Definition: imgui.cpp:7161
IMGUI_API const ImVec4 & GetStyleColorVec4(ImGuiCol idx)
Definition: imgui.cpp:1406
int FocusIdxTabRequestCurrent
#define STB_TEXTEDIT_K_DELETE
Definition: imgui.cpp:10009
ImGuiID ChildId
void clear()
Definition: imgui.h:1218
IMGUI_API void FocusableItemUnregister(ImGuiWindow *window)
Definition: imgui.cpp:2608
IMGUI_API void ItemSize(const ImVec2 &size, float text_offset_y=0.0f)
Definition: imgui.cpp:2180
IMGUI_API ImGuiMouseCursor GetMouseCursor()
Definition: imgui.cpp:4757
Definition: imgui.h:132
#define IM_COL32_B_SHIFT
Definition: imgui.h:1445
ImGuiWindow * MovingWindow
bool FontAllowUserScaling
Definition: imgui.h:1056
ImVec4 BackupValue
IMGUI_API bool SliderScalarN(const char *label, ImGuiDataType data_type, void *v, int components, const void *v_min, const void *v_max, const char *format=NULL, float power=1.0f)
Definition: imgui.cpp:9179
IMGUI_API void NewFrame()
Definition: imgui.cpp:3465
IMGUI_API void AddCircleFilled(const ImVec2 &centre, float radius, ImU32 col, int num_segments=12)
const ImWchar * ImStrbolW(const ImWchar *buf_mid_line, const ImWchar *buf_begin)
Definition: imgui.cpp:1062
GLbitfield flags
Definition: glcorearb.h:1605
float MouseClickedTime[5]
Definition: imgui.h:1135
ImWchar InputCharacters[16+1]
Definition: imgui.h:1104
IMGUI_API const char * SaveIniSettingsToMemory(size_t *out_ini_size=NULL)
Definition: imgui.cpp:3906
IMGUI_API bool DragFloat2(const char *label, float v[2], float v_speed=1.0f, float v_min=0.0f, float v_max=0.0f, const char *format="%.3f", float power=1.0f)
Definition: imgui.cpp:9469
IMGUI_API void Begin(int items_count, float items_height=-1.0f)
Definition: imgui.cpp:1889
ImTextureID TexID
Definition: imgui.h:1817
GLboolean GLboolean GLboolean b
Definition: glcorearb.h:1231
ImVec2 GetTL() const
IMGUI_API void PushStyleColor(ImGuiCol idx, ImU32 col)
Definition: imgui.cpp:6684
float GetCharAdvance(ImWchar c) const
Definition: imgui.h:1866
ImGuiID ScalarAsInputTextId
ImGuiTextBuffer LogClipboard
#define va_copy(dest, src)
Definition: imgui.cpp:1787
float DragDropAcceptIdCurrRectSurface
IMGUI_API const char * GetClipboardText()
Definition: imgui.cpp:2655
unsigned int _VtxCurrentIdx
Definition: imgui.h:1593
IMGUI_API void BeginGroup()
Definition: imgui.cpp:12552
IMGUI_API bool IsItemActive()
Definition: imgui.cpp:4777
int ImFormatStringV(char *buf, size_t buf_size, const char *fmt, va_list args)
Definition: imgui.cpp:1138
IMGUI_API void RenderColorRectWithAlphaCheckerboard(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, float grid_step, ImVec2 grid_off, float rounding=0.0f, int rounding_corners_flags=~0)
Definition: imgui.cpp:11664
float PrevLineTextBaseOffset
GLint GLint GLsizei GLint GLenum format
Definition: glcorearb.h:274
IMGUI_API bool BeginPopupModal(const char *name, bool *p_open=NULL, ImGuiWindowFlags flags=0)
Definition: imgui.cpp:5071
ImVector< TextRange > Filters
Definition: imgui.h:1297
int ImGuiCol
Definition: imgui.h:82
ImVec2 ImLineClosestPoint(const ImVec2 &a, const ImVec2 &b, const ImVec2 &p)
Definition: imgui.cpp:971
ImVec2 MouseClickedPos[5]
Definition: imgui.h:1134
IMGUI_API void PopButtonRepeat()
Definition: imgui.cpp:6664
bool KeyCtrl
Definition: imgui.h:1099
#define STB_TEXTEDIT_K_BACKSPACE
Definition: imgui.cpp:10010
ImGuiWindow * ParentWindow
ImFont * FontDefault
Definition: imgui.h:1057
IMGUI_API void RenderTextWrapped(ImVec2 pos, const char *text, const char *text_end, float wrap_width)
Definition: imgui.cpp:4316
IMGUI_API void ClearDragDrop()
Definition: imgui.cpp:13067
signed long long ImS64
Definition: imgui.h:115
IMGUI_API void RenderBullet(ImVec2 pos)
Definition: imgui.cpp:4437
ImGuiPopupPositionPolicy
Definition: imgui.cpp:5301
float x
Definition: imgui.h:134
ImVector< ImGuiPopupRef > OpenPopupStack
ImRect InnerClipRect
float IndentSpacing
Definition: imgui.h:1012
IMGUI_API void OpenPopup(const char *str_id)
Definition: imgui.cpp:4946
GLenum mode
Definition: glcorearb.h:265
int ImParseFormatPrecision(const char *fmt, int default_precision)
Definition: imgui.cpp:8737
GLuint64EXT * result
Definition: glcorearb.h:5393
ImGuiItemStatusFlags LastItemStatusFlags
int ImGuiSelectableFlags
Definition: imgui.h:102
IMGUI_API void CalcListClipping(int items_count, float items_height, int *out_items_display_start, int *out_items_display_end)
Definition: imgui.cpp:4525
IMGUI_API bool IsWindowAppearing()
Definition: imgui.cpp:7067
ImGuiID DragDropAcceptIdPrev
IMGUI_API ImVec2 GetWindowContentRegionMax()
Definition: imgui.cpp:7179
IMGUI_API bool ButtonEx(const char *label, const ImVec2 &size_arg=ImVec2(0, 0), ImGuiButtonFlags flags=0)
Definition: imgui.cpp:7760
ImDrawIdx * _IdxWritePtr
Definition: imgui.h:1595
ImVector< char > PrivateClipboard
#define STB_TEXTEDIT_K_WORDLEFT
Definition: imgui.cpp:10013
IMGUI_API float GetScrollMaxY()
Definition: imgui.cpp:7319
IMGUI_API float GetFrameHeight()
Definition: imgui.cpp:7203
ImGuiPlotArrayGetterData(const float *values, int stride)
Definition: imgui.cpp:9670
void * Data
Definition: imgui.h:1417
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glcorearb.h:2549
GLenum GLint GLint * precision
Definition: glcorearb.h:1934
ImVec2 DisplaySafeAreaPadding
Definition: imgui.h:1020
ImGuiCond SetWindowCollapsedAllowFlags
IMGUI_API bool InputDouble(const char *label, double *v, double step=0.0f, double step_fast=0.0f, const char *format="%.6f", ImGuiInputTextFlags extra_flags=0)
Definition: imgui.cpp:10815
#define IM_COL32_WHITE
Definition: imgui.h:1450
float BackupGroupOffsetX
IMGUI_API void BeginColumns(const char *str_id, int count, ImGuiColumnsFlags flags=0)
Definition: imgui.cpp:12827
IMGUI_API void AddRectFilled(const ImVec2 &a, const ImVec2 &b, ImU32 col, float rounding=0.0f, int rounding_corners_flags=ImDrawCornerFlags_All)
IMGUI_API void BulletText(const char *fmt,...) IM_FMTARGS(1)
Definition: imgui.cpp:8491
ImRect NavRectRel[2]
float SettingsDirtyTimer
ImGuiWindow * CurrentWindow
ImVec2 DisplayWindowPadding
Definition: imgui.h:1019
float NavWindowingHighlightTimer
float IniSavingRate
Definition: imgui.h:1043
float y
Definition: imgui.h:122
IMGUI_API bool InputFloat4(const char *label, float v[4], const char *format="%.3f", ImGuiInputTextFlags extra_flags=0)
Definition: imgui.cpp:10867
IMGUI_API void TextWrappedV(const char *fmt, va_list args) IM_FMTLIST(1)
Definition: imgui.cpp:7448
IMGUI_API void SetBool(ImGuiID key, bool val)
Definition: imgui.cpp:1647
ImGuiStyle Style
int MetricsRenderVertices
Definition: imgui.h:1124
IMGUI_API void appendfv(const char *fmt, va_list args) IM_FMTLIST(2)
Definition: imgui.cpp:1791
IMGUI_API bool TreeNodeExV(const char *str_id, ImGuiTreeNodeFlags flags, const char *fmt, va_list args) IM_FMTLIST(3)
Definition: imgui.cpp:8300
void Update(int count, float spacing, bool clear)
Definition: imgui.cpp:1836
IMGUI_API bool CollapsingHeader(const char *label, ImGuiTreeNodeFlags flags=0)
Definition: imgui.cpp:8257
ImDrawListFlags Flags
Definition: imgui.h:1588
ImRect InnerMainRect
ImVec2 FramePadding
Definition: imgui.h:1006
void(* ImGuiSizeCallback)(ImGuiSizeCallbackData *data)
Definition: imgui.h:106
IMGUI_API int GetColumnIndex()
Definition: imgui.cpp:12692
GLintptr offset
Definition: glcorearb.h:658
GLfloat GLfloat GLfloat GLfloat h
Definition: glcorearb.h:2011
GLenum GLenum dst
Definition: glcorearb.h:1802
int DragDropAcceptFrameCount
IMGUI_API bool IsKeyPressed(int user_key_index, bool repeat=true)
Definition: imgui.cpp:4633
IMGUI_API void TreePush(const char *str_id)
Definition: imgui.cpp:12992
IMGUI_API void PopFont()
Definition: imgui.cpp:6624
IMGUI_API void SetNextWindowFocus()
Definition: imgui.cpp:7138
char DataType[32+1]
Definition: imgui.h:1424
int ImStrnicmp(const char *str1, const char *str2, size_t count)
Definition: imgui.cpp:1026
iterator insert(const_iterator it, const value_type &v)
Definition: imgui.h:1249
int LogAutoExpandMaxDepth
IMGUI_API void TextColored(const ImVec4 &col, const char *fmt,...) IM_FMTARGS(2)
Definition: imgui.cpp:7425
float FramerateSecPerFrame[120]
void(* ImeSetInputScreenPosFn)(int x, int y)
Definition: imgui.h:1078
IMGUI_API void LabelText(const char *label, const char *fmt,...) IM_FMTARGS(2)
Definition: imgui.cpp:7607
IMGUI_API bool IsRectVisible(const ImVec2 &size)
Definition: imgui.cpp:12539
IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border=true, float rounding=0.0f)
Definition: imgui.cpp:4374
ImGuiWindowFlags Flags
ImVec2 GetTR() const
void PrimVtx(const ImVec2 &pos, const ImVec2 &uv, ImU32 col)
Definition: imgui.h:1667
IMGUI_API void LoadIniSettingsFromDisk(const char *ini_filename)
Definition: imgui.cpp:3808
IMGUI_API void SetInt(ImGuiID key, int val)
Definition: imgui.cpp:1636
ImDrawCallback UserCallback
Definition: imgui.h:1522
int TotalIdxCount
Definition: imgui.h:1679
float MouseDoubleClickMaxDist
Definition: imgui.h:1047
float GrabRounding
Definition: imgui.h:1017
ImVector< float > IndexAdvanceX
Definition: imgui.h:1844
IMGUI_API void EndFrame()
Definition: imgui.cpp:4067
ImGuiLayoutType ParentLayoutType
ImGuiBackendFlags BackendFlags
Definition: imgui.h:1040
float FontGlobalScale
Definition: imgui.h:1055
const char * LogFilename
Definition: imgui.h:1045
IMGUI_API ImGuiWindow * FindWindowByName(const char *name)
Definition: imgui.cpp:5420
IMGUI_API void PopClipRect()
Definition: imgui.cpp:4059
IMGUI_API bool TreeNodeEx(const char *label, ImGuiTreeNodeFlags flags=0)
Definition: imgui.cpp:8291
IMGUI_API void NavMoveRequestCancel()
Definition: imgui.cpp:2405
bool NavDisableHighlight
IMGUI_API float GetScrollX()
Definition: imgui.cpp:7304
ImDrawList DrawListInst
bool KeySuper
Definition: imgui.h:1102
#define STB_TEXTEDIT_K_WORDRIGHT
Definition: imgui.cpp:10014
#define IM_ARRAYSIZE(_ARR)
Definition: imgui.h:45
IMGUI_API void SetWindowFontScale(float scale)
Definition: imgui.cpp:7236
int FocusIdxAllCounter
IMGUI_API bool InputInt4(const char *label, int v[4], ImGuiInputTextFlags extra_flags=0)
Definition: imgui.cpp:10917
IMGUI_API ImGuiStyle()
Definition: imgui.cpp:823
IMGUI_API void OpenPopupEx(ImGuiID id)
Definition: imgui.cpp:4907
ImVec4 ColorPickerRef
void push_back(const value_type &v)
Definition: imgui.h:1245
#define IM_PI
ImVector< ImGuiWindow * > WindowsSortBuffer
IMGUI_API void NewLine()
Definition: imgui.cpp:12642
const float * Values
Definition: imgui.cpp:9667
ImVec2 GetBL() const
ImVector< ImGuiSettingsHandler > SettingsHandlers
float KeyRepeatDelay
Definition: imgui.h:1050
#define STB_TEXTEDIT_K_RIGHT
Definition: imgui.cpp:10002
IMGUI_API void BringWindowToBack(ImGuiWindow *window)
Definition: imgui.cpp:6490
iterator erase(const_iterator it)
Definition: imgui.h:1248
ImGuiDir NavMoveDir
float MouseDragThreshold
Definition: imgui.h:1048
int TotalVtxCount
Definition: imgui.h:1680
IMGUI_API void ScaleAllSizes(float scale_factor)
Definition: imgui.cpp:861
value_type * iterator
Definition: imgui.h:1204
IMGUI_API void PathArcTo(const ImVec2 &centre, float radius, float a_min, float a_max, int num_segments=10)
Definition: imgui_draw.cpp:901
ImGuiNavMoveResult NavMoveResultOther
ImVec2 MousePosPrev
Definition: imgui.h:1133
ImVec2 MouseDragMaxDistanceAbs[5]
Definition: imgui.h:1142
IMGUI_API void BeginTooltipEx(ImGuiWindowFlags extra_flags, bool override_previous_tooltip=true)
Definition: imgui.cpp:4860
ImVec2 TexUvWhitePixel
Definition: imgui.h:1828
IMGUI_API void LogFinish()
Definition: imgui.cpp:8016
IMGUI_API void EndColumns()
Definition: imgui.cpp:12891
int FocusIdxAllRequestNext
bool AntiAliasedLines
Definition: imgui.h:1022
ImVec2 ScrollbarSizes
constexpr float dx
unsigned int ImGuiID
Definition: imgui.h:80
IMGUI_API int * GetIntRef(ImGuiID key, int default_val=0)
Definition: imgui.cpp:1606
IMGUI_API void EndDragDropSource()
Definition: imgui.cpp:13168
IMGUI_API bool InvisibleButton(const char *str_id, const ImVec2 &size)
Definition: imgui.cpp:7843
IMGUI_API bool ButtonBehavior(const ImRect &bb, ImGuiID id, bool *out_hovered, bool *out_held, ImGuiButtonFlags flags=0)
Definition: imgui.cpp:7615
int AutoFitChildAxises
#define STB_TEXTEDIT_STRING
IMGUI_API void Separator()
Definition: imgui.cpp:12407
IMGUI_API float GetColumnWidth(int column_index=-1)
Definition: imgui.cpp:12761
ImVector< float > TextWrapPosStack
Definition: imgui.h:1837
IMGUI_API void SetNextTreeNodeOpen(bool is_open, ImGuiCond cond=0)
Definition: imgui.cpp:8389
IMGUI_API bool SliderBehavior(const ImRect &bb, ImGuiID id, ImGuiDataType data_type, void *v, const void *v_min, const void *v_max, const char *format, float power, ImGuiSliderFlags flags=0)
Definition: imgui.cpp:8985
IMGUI_API int CalcTypematicPressedRepeatAmount(float t, float t_prev, float repeat_delay, float repeat_rate)
Definition: imgui.cpp:4614
bool MouseDown[5]
Definition: imgui.h:1095
ImGuiID NavActivateDownId
IMGUI_API void PushClipRect(const ImVec2 &clip_rect_min, const ImVec2 &clip_rect_max, bool intersect_with_current_clip_rect)
Definition: imgui.cpp:4052
IMGUI_API bool ItemHoverable(const ImRect &bb, ImGuiID id)
Definition: imgui.cpp:2550
IMGUI_API bool MenuItem(const char *label, const char *shortcut=NULL, bool selected=false, bool enabled=true)
Definition: imgui.cpp:11325
ImVector< ImDrawList * > Layers[2]
IMGUI_API void PlotEx(ImGuiPlotType plot_type, const char *label, float(*values_getter)(void *data, int idx), void *data, int values_count, int values_offset, const char *overlay_text, float scale_min, float scale_max, ImVec2 graph_size)
Definition: imgui.cpp:9555
IMGUI_API ImGuiID GetActiveID()
Definition: imgui.cpp:2105
IMGUI_API void EndGroup()
Definition: imgui.cpp:12575
bool Delivery
Definition: imgui.h:1426
float NavInputsDownDurationPrev[ImGuiNavInput_COUNT]
Definition: imgui.h:1147
ImGuiConfigFlags ConfigFlags
Definition: imgui.h:1039
IMGUI_API void SetActiveID(ImGuiID id, ImGuiWindow *window)
Definition: imgui.cpp:2088
ImGuiWindow * NavWindow
IMGUI_API bool CloseButton(ImGuiID id, const ImVec2 &pos, float radius)
Definition: imgui.cpp:7863
IMGUI_API bool GetBool(ImGuiID key, bool default_val=false) const
Definition: imgui.cpp:1584
void PathLineTo(const ImVec2 &pos)
Definition: imgui.h:1636
GLint GLenum GLint x
Definition: glcorearb.h:402
IMGUI_API float GetScrollY()
Definition: imgui.cpp:7309
GLfloat GLfloat v1
Definition: glcorearb.h:810
IMGUI_API ImVec2 GetMouseDragDelta(int button=0, float lock_threshold=-1.0f)
Definition: imgui.cpp:4737
GLuint GLfloat * val
Definition: glcorearb.h:1617
Double_t yi[28]
Definition: Geometry.cxx:56
void * ImTextureID
Definition: imgui.h:74
float FrameBorderSize
Definition: imgui.h:1008
IMGUI_API void End()
Definition: imgui.cpp:1905
IMGUI_API bool InputInt3(const char *label, int v[3], ImGuiInputTextFlags extra_flags=0)
Definition: imgui.cpp:10912
#define STB_TEXTEDIT_K_UP
Definition: imgui.cpp:10003
IMGUI_API void SetCursorPos(const ImVec2 &local_pos)
Definition: imgui.cpp:7264
bool HoveredIdAllowOverlap
float BackupFloat[2]
int WantCaptureKeyboardNextFrame
IMGUI_API bool InputText(const char *label, char *buf, size_t buf_size, ImGuiInputTextFlags flags=0, ImGuiTextEditCallback callback=NULL, void *user_data=NULL)
Definition: imgui.cpp:10737
GLuint GLfloat GLfloat GLfloat x1
Definition: glcorearb.h:4876
bool NavMoveFromClampedRefRect
ImGuiID PopupId
IMGUI_API ImGuiIO()
Definition: imgui.cpp:884
int ImGuiKey
Definition: imgui.h:86
IMGUI_API void NavInitWindow(ImGuiWindow *window, bool force_reinit)
Definition: imgui.cpp:2767
GLint y
Definition: glcorearb.h:269
bool WantTextInput
Definition: imgui.h:1118
IMGUI_API bool InputFloat3(const char *label, float v[3], const char *format="%.3f", ImGuiInputTextFlags extra_flags=0)
Definition: imgui.cpp:10862
IMGUI_API float GetFloat(ImGuiID key, float default_val=0.0f) const
Definition: imgui.cpp:1589
IMGUI_API ImVec2 GetMousePos()
Definition: imgui.cpp:4713
IMGUI_API void SaveIniSettingsToDisk(const char *ini_filename)
Definition: imgui.cpp:3889
float Ascent
Definition: imgui.h:1854
IMGUI_API bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags=0)
Definition: imgui.cpp:8064
IMGUI_API void PopID()
Definition: imgui.cpp:8423
ImVec2 WindowTitleAlign
Definition: imgui.h:1001
IMGUI_API void PushAllowKeyboardFocus(bool allow_keyboard_focus)
Definition: imgui.cpp:6649
IMGUI_API ImU32 GetColorU32(ImGuiCol idx, float alpha_mul=1.0f)
Definition: imgui.cpp:1390
IMGUI_API float CalcWrapWidthForPos(const ImVec2 &pos, float wrap_pos_x)
Definition: imgui.cpp:2627
float MouseDragMaxDistanceSqr[5]
Definition: imgui.h:1143
ImVec2 MouseDelta
Definition: imgui.h:1127
unsigned int ElemCount
Definition: imgui.h:1519
const ImGuiResizeGripDef resize_grip_def[4]
Definition: imgui.cpp:5604
IMGUI_API void ResetMouseDragDelta(int button=0)
Definition: imgui.cpp:4749
ImVector< ImGuiColumnsSet > ColumnsStorage
IMGUI_API bool Begin(const char *name, bool *p_open=NULL, ImGuiWindowFlags flags=0)
Definition: imgui.cpp:5738
IMGUI_API void * GetVoidPtr(ImGuiID key) const
Definition: imgui.cpp:1597
IMGUI_API void LogButtons()
Definition: imgui.cpp:8040
ImGuiPayload DragDropPayload
const char * PrintFmt
Definition: imgui.cpp:8551
int MetricsActiveWindows
Definition: imgui.h:1126
ImVec2 DisplayFramebufferScale
Definition: imgui.h:1058
IMGUI_API void LogToFile(int max_depth=-1, const char *filename=NULL)
Definition: imgui.cpp:7973
IMGUI_API void BringWindowToFront(ImGuiWindow *window)
Definition: imgui.cpp:6475
float MenuBarHeight() const
float FallbackAdvanceX
Definition: imgui.h:1847
signed int ImS32
Definition: imgui.h:109
#define STB_TEXTEDIT_K_TEXTSTART
Definition: imgui.cpp:10007
const char * begin() const
Definition: imgui.h:1315
void clear()
Definition: imgui.h:1319
IMGUI_API void CloseCurrentPopup()
Definition: imgui.cpp:5015
ImVec2 ButtonTextAlign
Definition: imgui.h:1018
IMGUI_API bool DragInt2(const char *label, int v[2], float v_speed=1.0f, int v_min=0, int v_max=0, const char *format="%d")
Definition: imgui.cpp:9515
IMGUI_API void BulletTextV(const char *fmt, va_list args) IM_FMTLIST(1)
Definition: imgui.cpp:8467
float MouseWheel
Definition: imgui.h:1096
ImGuiID SourceParentId
Definition: imgui.h:1422
int ImGuiComboFlags
Definition: imgui.h:97
bool MouseDoubleClicked[5]
Definition: imgui.h:1137
GLint GLint GLsizei GLint GLenum GLenum type
Definition: glcorearb.h:274
ImVector< ImGuiGroupData > GroupStack
IMGUI_API bool SliderInt(const char *label, int *v, int v_min, int v_max, const char *format="%d")
Definition: imgui.cpp:9163
#define IMGUI_VERSION
Definition: imgui.h:25
IMGUI_API bool InputInt2(const char *label, int v[2], ImGuiInputTextFlags extra_flags=0)
Definition: imgui.cpp:10907
bool KeyAlt
Definition: imgui.h:1101
IMGUI_API bool InputTextEx(const char *label, char *buf, int buf_size, const ImVec2 &size_arg, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback=NULL, void *user_data=NULL)
Definition: imgui.cpp:10129
IMGUI_API void SetNextWindowContentSize(const ImVec2 &size)
Definition: imgui.cpp:7123
ImVector< ImGuiID > IDStack
ImGuiMouseCursor MouseCursor
ImGuiCond NextTreeNodeOpenCond
unsigned short ImWchar
Definition: imgui.h:81
float DragCurrentAccum
float KeyRepeatRate
Definition: imgui.h:1051
GLubyte GLubyte GLubyte GLubyte w
Definition: glcorearb.h:850
ImGuiNextWindowData NextWindowData
ImVec2 pos
Definition: imgui.h:1537
ImVec2 TouchExtraPadding
Definition: imgui.h:1011
IMGUI_API bool ColorPicker3(const char *label, float col[3], ImGuiColorEditFlags flags=0)
Definition: imgui.cpp:12081
IMGUI_API void RenderTextClipped(const ImVec2 &pos_min, const ImVec2 &pos_max, const char *text, const char *text_end, const ImVec2 *text_size_if_known, const ImVec2 &align=ImVec2(0, 0), const ImRect *clip_rect=NULL)
Definition: imgui.cpp:4334
ImGuiWindow * GetCurrentWindow()
IMGUI_API void SetAllInt(int val)
Definition: imgui.cpp:1674
float DeclColumns(float w0, float w1, float w2)
Definition: imgui.cpp:1853
IMGUI_API void PlotLines(const char *label, const float *values, int values_count, int values_offset=0, const char *overlay_text=NULL, float scale_min=FLT_MAX, float scale_max=FLT_MAX, ImVec2 graph_size=ImVec2(0, 0), int stride=sizeof(float))
Definition: imgui.cpp:9680
GLboolean r
Definition: glcorearb.h:1231
void Floor()
IMGUI_API void Columns(int count=1, const char *id=NULL, bool border=true)
Definition: imgui.cpp:12959
IMGUI_API void EndPopup()
Definition: imgui.cpp:5111
IMGUI_API bool BeginMenuBar()
Definition: imgui.cpp:11412
IMGUI_API bool InputTextMultiline(const char *label, char *buf, size_t buf_size, const ImVec2 &size=ImVec2(0, 0), ImGuiInputTextFlags flags=0, ImGuiTextEditCallback callback=NULL, void *user_data=NULL)
Definition: imgui.cpp:10743
IMGUI_API void TextWrapped(const char *fmt,...) IM_FMTARGS(1)
Definition: imgui.cpp:7456
IMGUI_API bool VSliderScalar(const char *label, const ImVec2 &size, ImGuiDataType data_type, void *v, const void *v_min, const void *v_max, const char *format=NULL, float power=1.0f)
Definition: imgui.cpp:9106
GLint GLenum GLboolean GLsizei stride
Definition: glcorearb.h:865
ImRect OuterRectClipped
void IM_DELETE(T *p)
Definition: imgui.h:1261
ImU32 TreeDepthMayJumpToParentOnPop
int ImGuiMouseCursor
Definition: imgui.h:88
IMGUI_API void PushClipRectFullScreen()
Definition: imgui_draw.cpp:461
IMGUI_API void PopItemWidth()
Definition: imgui.cpp:6572
T * Data
Definition: imgui.h:1201
IMGUI_API void TextDisabled(const char *fmt,...) IM_FMTARGS(1)
Definition: imgui.cpp:7440
void ImStrTrimBlanks(char *buf)
Definition: imgui.cpp:1092
IMGUI_API ImVec2 CalcTextSizeA(float size, float max_width, float wrap_width, const char *text_begin, const char *text_end=NULL, const char **remaining=NULL) const
IMGUI_API bool TreeNodeV(const char *str_id, const char *fmt, va_list args) IM_FMTLIST(2)
Definition: imgui.cpp:8322
IMGUI_API void TreeAdvanceToLabelPos()
Definition: imgui.cpp:8376
ImGuiCond SizeConstraintCond
IMGUI_API bool GetMouseCursorTexData(ImGuiMouseCursor cursor, ImVec2 *out_offset, ImVec2 *out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2])
IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_x, float default_y)
Definition: imgui.cpp:2614
float WindowBorderSize
Definition: imgui.h:999
void Translate(const ImVec2 &d)
IMGUI_API ImGuiSettingsHandler * FindSettingsHandler(const char *type_name)
Definition: imgui.cpp:3818
IMGUI_API void SetCursorPosX(float x)
Definition: imgui.cpp:7271
int ImGuiFocusedFlags
Definition: imgui.h:99
IMGUI_API bool Selectable(const char *label, bool selected=false, ImGuiSelectableFlags flags=0, const ImVec2 &size=ImVec2(0, 0))
Definition: imgui.cpp:11133
ImVector< char > InitialText
FILE * ImFileOpen(const char *filename, const char *mode)
Definition: imgui.cpp:1473
iterator end()
Definition: imgui.h:1221
ImFontAtlas * ContainerAtlas
Definition: imgui.h:1853
IMGUI_API float GetScrollMaxX()
Definition: imgui.cpp:7314
IMGUI_API bool ListBoxHeader(const char *label, const ImVec2 &size=ImVec2(0, 0))
Definition: imgui.cpp:11232
ImGuiWindow * Window
ImVec2 BackupCursorMaxPos
ImVec2 SizeContents
const char * end() const
Definition: imgui.h:1288
float KeysDownDuration[512]
Definition: imgui.h:1144
ImGuiStorage WindowsById
float Scale
Definition: imgui.h:1841
IMGUI_API void Dummy(const ImVec2 &size)
Definition: imgui.cpp:12528
void Clear()
Definition: imgui.h:1429
bool NextTreeNodeOpenVal
IMGUI_API bool ColorButton(const char *desc_id, const ImVec4 &col, ImGuiColorEditFlags flags=0, ImVec2 size=ImVec2(0, 0))
Definition: imgui.cpp:11716
#define IMGUI_PAYLOAD_TYPE_COLOR_3F
Definition: imgui.h:724
ImVector< Pair > Data
Definition: imgui.h:1344
IMGUI_API void ClearActiveID()
Definition: imgui.cpp:2133
ImGuiStorage * StateStorage
bool AntiAliasedFill
Definition: imgui.h:1023
ImVec2 Min
IMGUI_API void LogText(const char *fmt,...) IM_FMTARGS(1)
Definition: imgui.cpp:4221
IMGUI_API bool IsWindowCollapsed()
Definition: imgui.cpp:7061
IMGUI_API void InsertChars(int pos, const char *text, const char *text_end=NULL)
Definition: imgui.cpp:10050
float MouseDownDuration[5]
Definition: imgui.h:1140
IMGUI_API void ProgressBar(float fraction, const ImVec2 &size_arg=ImVec2(-1, 0), const char *overlay=NULL)
Definition: imgui.cpp:9703
IMGUI_API ImVec2 GetItemRectSize()
Definition: imgui.cpp:4845
ImGuiID NavInputId
ImGuiWindow * HoveredWindow
ImGuiID DragDropAcceptIdCurr
int ImGuiDataType
Definition: imgui.h:83
bool KeysDown[512]
Definition: imgui.h:1103
ImVec2 WindowPadding
Definition: imgui.h:997
IMGUI_API float GetWindowContentRegionWidth()
Definition: imgui.cpp:7185
IMGUI_API float GetTreeNodeToLabelSpacing()
Definition: imgui.cpp:8383
bool Overlaps(const ImRect &r) const
float BackupCurrentLineHeight
IMGUI_API ImDrawListSharedData * GetDrawListSharedData()
Definition: imgui.cpp:2761
IMGUI_API void PrimReserve(int idx_count, int vtx_count)
Definition: imgui_draw.cpp:566
#define IM_OFFSETOF(_TYPE, _MEMBER)
Definition: imgui.h:46
float WindowRounding
Definition: imgui.h:998
bool NavDisableMouseHover
IMGUI_API void SetStateStorage(ImGuiStorage *storage)
Definition: imgui.cpp:7387
IMGUI_API void ChannelsSplit(int channels_count)
Definition: imgui_draw.cpp:486
ImVector< unsigned char > DragDropPayloadBufHeap
IMGUI_API ImFont * GetFont()
Definition: imgui.cpp:7221
IMGUI_API void EndChild()
Definition: imgui.cpp:5227
IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags)
Definition: imgui.cpp:5026
IMGUI_API ImVec2 GetFontTexUvWhitePixel()
Definition: imgui.cpp:7231
IMGUI_API bool InputFloat2(const char *label, float v[2], const char *format="%.3f", ImGuiInputTextFlags extra_flags=0)
Definition: imgui.cpp:10857
IMGUI_API void SetScrollX(float scroll_x)
Definition: imgui.cpp:7324
ImVec2 PlatformImeLastPos
void Add(const ImVec2 &p)
IMGUI_API bool IsClippedEx(const ImRect &bb, ImGuiID id, bool clip_even_when_logged)
Definition: imgui.cpp:2572
ImVec2 GetSize() const
IMGUI_API void SetColumnOffset(int column_index, float offset_x)
Definition: imgui.cpp:12772
float ScrollbarSize
Definition: imgui.h:1014
IMGUI_API ImVec2 GetWindowPos()
Definition: imgui.cpp:6946
IMGUI_API void SetNextWindowCollapsed(bool collapsed, ImGuiCond cond=0)
Definition: imgui.cpp:7130
IMGUI_API bool IsMouseReleased(int button)
Definition: imgui.cpp:4688
ImRect LastItemDisplayRect
IMGUI_API bool BeginPopupContextVoid(const char *str_id=NULL, int mouse_button=1)
Definition: imgui.cpp:5160
bool OptMacOSXBehaviors
Definition: imgui.h:1063
IMGUI_API bool IsItemVisible()
Definition: imgui.cpp:4817
float AdvanceX
Definition: imgui.h:1717
IMGUI_API void SetItemAllowOverlap()
Definition: imgui.cpp:4824
IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2 &size, const ImVec2 &uv0=ImVec2(0, 0), const ImVec2 &uv1=ImVec2(1, 1), const ImVec4 &tint_col=ImVec4(1, 1, 1, 1), const ImVec4 &border_col=ImVec4(0, 0, 0, 0))
Definition: imgui.cpp:7892
ImGuiStyleVar VarIdx
IMGUI_API void TextV(const char *fmt, va_list args) IM_FMTLIST(1)
Definition: imgui.cpp:7399
ImGuiWindow * GetCurrentWindowRead()
IMGUI_API void StyleColorsDark(ImGuiStyle *dst=NULL)
Definition: imgui_draw.cpp:151
ImVector< ImGuiPopupRef > CurrentPopupStack
ImVec2 ScrollTarget
float y
Definition: imgui.h:134
ImVector< float > ItemWidthStack
#define STB_TEXTEDIT_K_LEFT
Definition: imgui.cpp:10001
float x
Definition: imgui.h:122
IMGUI_API bool BeginCombo(const char *label, const char *preview_value, ImGuiComboFlags flags=0)
Definition: imgui.cpp:10930
const char *(* GetClipboardTextFn)(void *user_data)
Definition: imgui.h:1072
ImGuiCond SetWindowSizeAllowFlags
void(* ReadLineFn)(ImGuiContext *ctx, ImGuiSettingsHandler *handler, void *entry, const char *line)
float PopupRounding
Definition: imgui.h:1004
ImVector< ImGuiWindow * > ChildWindows
IMGUI_API void Value(const char *prefix, bool b)
Definition: imgui.cpp:13034
ImVec4 Colors[ImGuiCol_COUNT]
Definition: imgui.h:1025
ImVector< ImFont * > Fonts
Definition: imgui.h:1829
char TempBuffer[1024 *3+1]
int BeginOrderWithinParent
ImGuiID NavNextActivateId
ImGuiInputSource ActiveIdSource
IMGUI_API bool IsWindowHovered(ImGuiHoveredFlags flags=0)
Definition: imgui.cpp:6865
IMGUI_API void TextDisabledV(const char *fmt, va_list args) IM_FMTLIST(1)
Definition: imgui.cpp:7433
ImGuiID NavJustMovedToId
value_type & back()
Definition: imgui.h:1225
IMGUI_API bool SmallButton(const char *label)
Definition: imgui.cpp:7805
float CalcExtraSpace(float avail_w)
Definition: imgui.cpp:1864
GLenum src
Definition: glcorearb.h:1802
IMGUI_API bool InputScalarAsWidgetReplacement(const ImRect &bb, ImGuiID id, const char *label, ImGuiDataType data_type, void *data_ptr, const char *format)
Definition: imgui.cpp:8657
IMGUI_API bool DragFloat3(const char *label, float v[3], float v_speed=1.0f, float v_min=0.0f, float v_max=0.0f, const char *format="%.3f", float power=1.0f)
Definition: imgui.cpp:9474
float NavWindowingHighlightAlpha